From mboxrd@z Thu Jan 1 00:00:00 1970 From: Peter =?utf-8?q?M=C3=BCller?= To: development@lists.ipfire.org Subject: Re: [PATCH] nmap: Update to work with python3 Date: Fri, 14 May 2021 17:53:27 +0200 Message-ID: <00d822a8-d3da-6086-e04c-d2cb5cda2c20@ipfire.org> In-Reply-To: <517BBBEB-0691-4293-85F1-96E588B18B3A@ipfire.org> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============2213826832317163585==" List-Id: --===============2213826832317163585== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Hello Adolf, hello Michael, hello *, personally, I would vote for dropping ndiff as well, then. While a port scanning tool makes sense on a firewall to me (in certain scenar= ios), I guess most IT security folks will compare the results of such scans on a dedicated machi= ne, anyway... Thanks, and best regards, Peter M=C3=BCller > Yay, we found the first blocker. >=20 > This was almost going too smooth for my feeling :) >=20 > I would also disagree with maintaining our own copy of ndiff that has been = ported to Python 3. That will cause extra work every time the package is bein= g updated and probably will introduce new bugs which have to be fixed by us i= nstead of upstream. >=20 > We have two options then: >=20 > a) Do we desperately need ndiff or can we just disable it? >=20 > Fedora for example disabled it (https://src.fedoraproject.org/rpms/nmap/blo= b/rawhide/f/nmap.spec#_105) >=20 > So does Gentoo (https://gitweb.gentoo.org/repo/gentoo.git/tree/net-analyzer= /nmap/nmap-7.91-r2.ebuild#n106) >=20 > b) Wait for upstream to merge one of the proposed ports and be happy. But i= f you say they don=E2=80=99t really care much I would recommend we follow the= crowd and go with a). >=20 > -Michael >=20 >> On 14 May 2021, at 11:13, Adolf Belka wrote: >> >> Hi Peter, >> >> On 14/05/2021 09:19, Peter M=C3=BCller wrote: >>> Hello Adolf, >>> thank you for this patch. >>> While I generally agree with your intention, I am not quite sure if ndiff= "survived" the execution >>> of 2to3. Personally, I have not used ndiff for a long time, hence it woul= d be interesting to see if >>> the 2to3 result is bug-compatible to the original one. :-) >> Thanks for that feedback. I have now done a more detailed trawl through th= e issues section of the nmap git repository. It appears that several people = have pushed updates for ndiff since 2019 but so far none of them have been ac= cepted. They look to be a 2to3 conversion with some additional cmp and other = changes. So my change may not be sufficient. I am not sure how to test if it = would work but it may not be worth pursuing if the people in the nmap issues = are having a problem getting a >>> Let's hope the ndiff upstream switches to Python 3 soon... >> It looks like the official ndiff porting to python3 is being combined with= porting of zenmap as well and that requires gtk changes which are much more = problematic. fyodor from nmap has said it is being worked on but out of 609 o= pen nmap and ncap issues the zenmap/ndiff one is at number 11. He says that t= his is important but some of the other issues are harder to workaround than z= enmap/ndiff where you just need to install python2. This input was from Mar 2= 021. Apparently some distros are starting to drop nmap because they no longer= have python2 and nmap fails to build with python3. >> >> >> I suspect that nmap will have to stay with python2 for some more time and = so IPFire will also have to keep python2 in place for that build. :-( >> >> Regards, >> Adolf. >>> Acked-by: Peter M=C3=BCller >>> Thanks, and best regards, >>> Peter M=C3=BCller >>>> - Added PYTHON=3Dpython3 prior to configure. This then builds nmap with >>>> python3. ndiff is written as python2 only and the Makefile will not >>>> build ndiff if python2.x is not available. Complicated check system >>>> that I was unable to understand and patch to check for python3 instead >>>> - Converted ndiff.py and associated setup.py with 2to3 converter and >>>> created a patch to apply to ndiff.py and setup.py in the lfs >>>> - Added --without-ndiff to configure so Makefile does not check if it can >>>> build ndiff with python2 or not. Added separate command to build >>>> ndiff.py with python3 >>>> >>>> Signed-off-by: Adolf Belka >>>> --- >>>> config/rootfiles/packages/nmap | 3 +- >>>> lfs/nmap | 16 +- >>>> src/patches/nmap-7.91-2to3-ndiff.patch | 1246 ++++++++++++++++++++++++ >>>> 3 files changed, 1257 insertions(+), 8 deletions(-) >>>> create mode 100644 src/patches/nmap-7.91-2to3-ndiff.patch >>>> >>>> diff --git a/config/rootfiles/packages/nmap b/config/rootfiles/packages/= nmap >>>> index 028408ca0..837c81a71 100644 >>>> --- a/config/rootfiles/packages/nmap >>>> +++ b/config/rootfiles/packages/nmap >>>> @@ -2,8 +2,7 @@ usr/bin/ndiff >>>> usr/bin/nmap >>>> usr/bin/nping >>>> #usr/bin/uninstall_ndiff >>>> -usr/lib/python2.7/site-packages/ndiff.py >>>> -#usr/lib/python2.7/site-packages/ndiff.pyc >>>> +usr/lib/python3.8/site-packages/ndiff.py >>>> #usr/share/man/de/man1/nmap.1 >>>> #usr/share/man/es/man1/nmap.1 >>>> #usr/share/man/fr/man1/nmap.1 >>>> diff --git a/lfs/nmap b/lfs/nmap >>>> index d0d4d3428..83b83a511 100644 >>>> --- a/lfs/nmap >>>> +++ b/lfs/nmap >>>> @@ -32,7 +32,7 @@ DL_FROM =3D $(URL_IPFIRE) >>>> DIR_APP =3D $(DIR_SRC)/$(THISAPP) >>>> TARGET =3D $(DIR_INFO)/$(THISAPP) >>>> PROG =3D nmap >>>> -PAK_VER =3D 12 >>>> +PAK_VER =3D 13 >>>> DEPS =3D >>>> @@ -77,12 +77,16 @@ $(subst %,%_MD5,$(objects)) : >>>> $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects)) >>>> @$(PREBUILD) >>>> @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar jxf $(DIR_DL)/$(DL_FILE) >>>> + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/nmap-7.91-2to3-nd= iff.patch >>>> $(UPDATE_AUTOMAKE) >>>> - cd $(DIR_APP) && ./configure \ >>>> - --prefix=3D/usr \ >>>> - --without-nmapfe \ >>>> - --without-zenmap \ >>>> - --without-ncat >>>> + cd $(DIR_APP) && PYTHON=3Dpython3 \ >>>> + ./configure \ >>>> + --prefix=3D/usr \ >>>> + --without-nmapfe \ >>>> + --without-zenmap \ >>>> + --without-ncat \ >>>> + --without-ndiff >>>> + cd $(DIR_APP)/ndiff && python3 setup.py install >>>> cd $(DIR_APP) && make $(MAKETUNING) $(EXTRA_MAKE) >>>> cd $(DIR_APP) && make install >>>> @rm -rf $(DIR_APP) >>>> diff --git a/src/patches/nmap-7.91-2to3-ndiff.patch b/src/patches/nmap-7= .91-2to3-ndiff.patch >>>> new file mode 100644 >>>> index 000000000..5523a9d30 >>>> --- /dev/null >>>> +++ b/src/patches/nmap-7.91-2to3-ndiff.patch >>>> @@ -0,0 +1,1246 @@ >>>> +diff -Naur nmap-7.91.orig/ndiff/ndiff.py nmap-7.91/ndiff/ndiff.py >>>> +--- nmap-7.91.orig/ndiff/ndiff.py 2020-10-02 15:55:49.000000000 +0200 >>>> ++++ nmap-7.91/ndiff/ndiff.py 2021-05-10 20:42:14.475398029 +0200 >>>> +@@ -26,11 +26,11 @@ >>>> + import xml.sax >>>> + import xml.sax.saxutils >>>> + import xml.dom.minidom >>>> +-from StringIO import StringIO >>>> ++from io import StringIO >>>> + >>>> + verbose =3D False >>>> + >>>> +-NDIFF_XML_VERSION =3D u"1" >>>> ++NDIFF_XML_VERSION =3D "1" >>>> + >>>> + >>>> + class OverrideEntityResolver(xml.sax.handler.EntityResolver): >>>> +@@ -75,35 +75,35 @@ >>>> + def write_nmaprun_open(self, writer): >>>> + attrs =3D {} >>>> + if self.scanner is not None: >>>> +- attrs[u"scanner"] =3D self.scanner >>>> ++ attrs["scanner"] =3D self.scanner >>>> + if self.args is not None: >>>> +- attrs[u"args"] =3D self.args >>>> ++ attrs["args"] =3D self.args >>>> + if self.start_date is not None: >>>> +- attrs[u"start"] =3D "%d" % time.mktime(self.start_date.tim= etuple()) >>>> +- attrs[u"startstr"] =3D self.start_date.strftime( >>>> ++ attrs["start"] =3D "%d" % time.mktime(self.start_date.time= tuple()) >>>> ++ attrs["startstr"] =3D self.start_date.strftime( >>>> + "%a %b %d %H:%M:%S %Y") >>>> + if self.version is not None: >>>> +- attrs[u"version"] =3D self.version >>>> +- writer.startElement(u"nmaprun", attrs) >>>> ++ attrs["version"] =3D self.version >>>> ++ writer.startElement("nmaprun", attrs) >>>> + >>>> + def write_nmaprun_close(self, writer): >>>> +- writer.endElement(u"nmaprun") >>>> ++ writer.endElement("nmaprun") >>>> + >>>> + def nmaprun_to_dom_fragment(self, document): >>>> + frag =3D document.createDocumentFragment() >>>> +- elem =3D document.createElement(u"nmaprun") >>>> ++ elem =3D document.createElement("nmaprun") >>>> + if self.scanner is not None: >>>> +- elem.setAttribute(u"scanner", self.scanner) >>>> ++ elem.setAttribute("scanner", self.scanner) >>>> + if self.args is not None: >>>> +- elem.setAttribute(u"args", self.args) >>>> ++ elem.setAttribute("args", self.args) >>>> + if self.start_date is not None: >>>> + elem.setAttribute( >>>> +- u"start", "%d" % time.mktime(self.start_date.timet= uple())) >>>> ++ "start", "%d" % time.mktime(self.start_date.timetu= ple())) >>>> + elem.setAttribute( >>>> +- u"startstr", >>>> ++ "startstr", >>>> + self.start_date.strftime("%a %b %d %H:%M:%S %Y")) >>>> + if self.version is not None: >>>> +- elem.setAttribute(u"version", self.version) >>>> ++ elem.setAttribute("version", self.version) >>>> + frag.appendChild(elem) >>>> + return frag >>>> + >>>> +@@ -133,17 +133,17 @@ >>>> + >>>> + def format_name(self): >>>> + """Return a human-readable identifier for this host.""" >>>> +- address_s =3D u", ".join(a.s for a in sorted(self.addresses)) >>>> +- hostname_s =3D u", ".join(sorted(self.hostnames)) >>>> ++ address_s =3D ", ".join(a.s for a in sorted(self.addresses)) >>>> ++ hostname_s =3D ", ".join(sorted(self.hostnames)) >>>> + if len(hostname_s) > 0: >>>> + if len(address_s) > 0: >>>> +- return u"%s (%s)" % (hostname_s, address_s) >>>> ++ return "%s (%s)" % (hostname_s, address_s) >>>> + else: >>>> + return hostname_s >>>> + elif len(address_s) > 0: >>>> + return address_s >>>> + else: >>>> +- return u"" >>>> ++ return "" >>>> + >>>> + def add_port(self, port): >>>> + self.ports[port.spec] =3D port >>>> +@@ -160,46 +160,46 @@ >>>> + return state is None or state in self.extraports >>>> + >>>> + def extraports_string(self): >>>> +- list =3D [(count, state) for (state, count) in self.extraports= .items()] >>>> ++ list =3D [(count, state) for (state, count) in list(self.extra= ports.items())] >>>> + # Reverse-sort by count. >>>> + list.sort(reverse=3DTrue) >>>> +- return u", ".join( >>>> +- [u"%d %s ports" % (count, state) for (count, state) in= list]) >>>> ++ return ", ".join( >>>> ++ ["%d %s ports" % (count, state) for (count, state) in = list]) >>>> + >>>> + def state_to_dom_fragment(self, document): >>>> + frag =3D document.createDocumentFragment() >>>> + if self.state is not None: >>>> +- elem =3D document.createElement(u"status") >>>> +- elem.setAttribute(u"state", self.state) >>>> ++ elem =3D document.createElement("status") >>>> ++ elem.setAttribute("state", self.state) >>>> + frag.appendChild(elem) >>>> + return frag >>>> + >>>> + def hostname_to_dom_fragment(self, document, hostname): >>>> + frag =3D document.createDocumentFragment() >>>> +- elem =3D document.createElement(u"hostname") >>>> +- elem.setAttribute(u"name", hostname) >>>> ++ elem =3D document.createElement("hostname") >>>> ++ elem.setAttribute("name", hostname) >>>> + frag.appendChild(elem) >>>> + return frag >>>> + >>>> + def extraports_to_dom_fragment(self, document): >>>> + frag =3D document.createDocumentFragment() >>>> +- for state, count in self.extraports.items(): >>>> +- elem =3D document.createElement(u"extraports") >>>> +- elem.setAttribute(u"state", state) >>>> +- elem.setAttribute(u"count", unicode(count)) >>>> ++ for state, count in list(self.extraports.items()): >>>> ++ elem =3D document.createElement("extraports") >>>> ++ elem.setAttribute("state", state) >>>> ++ elem.setAttribute("count", str(count)) >>>> + frag.appendChild(elem) >>>> + return frag >>>> + >>>> + def os_to_dom_fragment(self, document, os): >>>> + frag =3D document.createDocumentFragment() >>>> +- elem =3D document.createElement(u"osmatch") >>>> +- elem.setAttribute(u"name", os) >>>> ++ elem =3D document.createElement("osmatch") >>>> ++ elem.setAttribute("name", os) >>>> + frag.appendChild(elem) >>>> + return frag >>>> + >>>> + def to_dom_fragment(self, document): >>>> + frag =3D document.createDocumentFragment() >>>> +- elem =3D document.createElement(u"host") >>>> ++ elem =3D document.createElement("host") >>>> + >>>> + if self.state is not None: >>>> + elem.appendChild(self.state_to_dom_fragment(document)) >>>> +@@ -208,13 +208,13 @@ >>>> + elem.appendChild(addr.to_dom_fragment(document)) >>>> + >>>> + if len(self.hostnames) > 0: >>>> +- hostnames_elem =3D document.createElement(u"hostnames") >>>> ++ hostnames_elem =3D document.createElement("hostnames") >>>> + for hostname in self.hostnames: >>>> + hostnames_elem.appendChild( >>>> + self.hostname_to_dom_fragment(document, hostna= me)) >>>> + elem.appendChild(hostnames_elem) >>>> + >>>> +- ports_elem =3D document.createElement(u"ports") >>>> ++ ports_elem =3D document.createElement("ports") >>>> + ports_elem.appendChild(self.extraports_to_dom_fragment(documen= t)) >>>> + for port in sorted(self.ports.values()): >>>> + if not self.is_extraports(port.state): >>>> +@@ -223,13 +223,13 @@ >>>> + elem.appendChild(ports_elem) >>>> + >>>> + if len(self.os) > 0: >>>> +- os_elem =3D document.createElement(u"os") >>>> ++ os_elem =3D document.createElement("os") >>>> + for os in self.os: >>>> + os_elem.appendChild(self.os_to_dom_fragment(document, = os)) >>>> + elem.appendChild(os_elem) >>>> + >>>> + if len(self.script_results) > 0: >>>> +- hostscript_elem =3D document.createElement(u"hostscript") >>>> ++ hostscript_elem =3D document.createElement("hostscript") >>>> + for sr in self.script_results: >>>> + hostscript_elem.appendChild(sr.to_dom_fragment(documen= t)) >>>> + elem.appendChild(hostscript_elem) >>>> +@@ -261,21 +261,21 @@ >>>> + return self.s >>>> + >>>> + def new(type, s): >>>> +- if type =3D=3D u"ipv4": >>>> ++ if type =3D=3D "ipv4": >>>> + return IPv4Address(s) >>>> +- elif type =3D=3D u"ipv6": >>>> ++ elif type =3D=3D "ipv6": >>>> + return IPv6Address(s) >>>> +- elif type =3D=3D u"mac": >>>> ++ elif type =3D=3D "mac": >>>> + return MACAddress(s) >>>> + else: >>>> +- raise ValueError(u"Unknown address type %s." % type) >>>> ++ raise ValueError("Unknown address type %s." % type) >>>> + new =3D staticmethod(new) >>>> + >>>> + def to_dom_fragment(self, document): >>>> + frag =3D document.createDocumentFragment() >>>> +- elem =3D document.createElement(u"address") >>>> +- elem.setAttribute(u"addr", self.s) >>>> +- elem.setAttribute(u"addrtype", self.type) >>>> ++ elem =3D document.createElement("address") >>>> ++ elem.setAttribute("addr", self.s) >>>> ++ elem.setAttribute("addrtype", self.type) >>>> + frag.appendChild(elem) >>>> + return frag >>>> + >>>> +@@ -284,21 +284,21 @@ >>>> + >>>> + >>>> + class IPv4Address(Address): >>>> +- type =3D property(lambda self: u"ipv4") >>>> ++ type =3D property(lambda self: "ipv4") >>>> + >>>> + def sort_key(self): >>>> + return (0, self.s) >>>> + >>>> + >>>> + class IPv6Address(Address): >>>> +- type =3D property(lambda self: u"ipv6") >>>> ++ type =3D property(lambda self: "ipv6") >>>> + >>>> + def sort_key(self): >>>> + return (1, self.s) >>>> + >>>> + >>>> + class MACAddress(Address): >>>> +- type =3D property(lambda self: u"mac") >>>> ++ type =3D property(lambda self: "mac") >>>> + >>>> + def sort_key(self): >>>> + return (2, self.s) >>>> +@@ -317,12 +317,12 @@ >>>> + >>>> + def state_string(self): >>>> + if self.state is None: >>>> +- return u"unknown" >>>> ++ return "unknown" >>>> + else: >>>> +- return unicode(self.state) >>>> ++ return str(self.state) >>>> + >>>> + def spec_string(self): >>>> +- return u"%d/%s" % self.spec >>>> ++ return "%d/%s" % self.spec >>>> + >>>> + def __hash__(self): >>>> + return hash(self.spec) >>>> +@@ -336,12 +336,12 @@ >>>> + >>>> + def to_dom_fragment(self, document): >>>> + frag =3D document.createDocumentFragment() >>>> +- elem =3D document.createElement(u"port") >>>> +- elem.setAttribute(u"portid", unicode(self.spec[0])) >>>> +- elem.setAttribute(u"protocol", self.spec[1]) >>>> ++ elem =3D document.createElement("port") >>>> ++ elem.setAttribute("portid", str(self.spec[0])) >>>> ++ elem.setAttribute("protocol", self.spec[1]) >>>> + if self.state is not None: >>>> +- state_elem =3D document.createElement(u"state") >>>> +- state_elem.setAttribute(u"state", self.state) >>>> ++ state_elem =3D document.createElement("state") >>>> ++ state_elem.setAttribute("state", self.state) >>>> + elem.appendChild(state_elem) >>>> + elem.appendChild(self.service.to_dom_fragment(document)) >>>> + for sr in self.script_results: >>>> +@@ -385,7 +385,7 @@ >>>> + if len(parts) =3D=3D 0: >>>> + return None >>>> + else: >>>> +- return u"/".join(parts) >>>> ++ return "/".join(parts) >>>> + >>>> + def version_string(self): >>>> + """Get a string like in the VERSION column of Nmap output.""" >>>> +@@ -395,17 +395,17 @@ >>>> + if self.version is not None: >>>> + parts.append(self.version) >>>> + if self.extrainfo is not None: >>>> +- parts.append(u"(%s)" % self.extrainfo) >>>> ++ parts.append("(%s)" % self.extrainfo) >>>> + >>>> + if len(parts) =3D=3D 0: >>>> + return None >>>> + else: >>>> +- return u" ".join(parts) >>>> ++ return " ".join(parts) >>>> + >>>> + def to_dom_fragment(self, document): >>>> + frag =3D document.createDocumentFragment() >>>> +- elem =3D document.createElement(u"service") >>>> +- for attr in (u"name", u"product", u"version", u"extrainfo", u"= tunnel"): >>>> ++ elem =3D document.createElement("service") >>>> ++ for attr in ("name", "product", "version", "extrainfo", "tunne= l"): >>>> + v =3D getattr(self, attr) >>>> + if v is None: >>>> + continue >>>> +@@ -435,53 +435,53 @@ >>>> + result =3D [] >>>> + lines =3D self.output.splitlines() >>>> + if len(lines) > 0: >>>> +- lines[0] =3D self.id + u": " + lines[0] >>>> ++ lines[0] =3D self.id + ": " + lines[0] >>>> + for line in lines[:-1]: >>>> +- result.append(u"| " + line) >>>> ++ result.append("| " + line) >>>> + if len(lines) > 0: >>>> +- result.append(u"|_ " + lines[-1]) >>>> ++ result.append("|_ " + lines[-1]) >>>> + return result >>>> + >>>> + def to_dom_fragment(self, document): >>>> + frag =3D document.createDocumentFragment() >>>> +- elem =3D document.createElement(u"script") >>>> +- elem.setAttribute(u"id", self.id) >>>> +- elem.setAttribute(u"output", self.output) >>>> ++ elem =3D document.createElement("script") >>>> ++ elem.setAttribute("id", self.id) >>>> ++ elem.setAttribute("output", self.output) >>>> + frag.appendChild(elem) >>>> + return frag >>>> + >>>> + >>>> + def format_banner(scan): >>>> + """Format a startup banner more or less like Nmap does.""" >>>> +- scanner =3D u"Nmap" >>>> +- if scan.scanner is not None and scan.scanner !=3D u"nmap": >>>> ++ scanner =3D "Nmap" >>>> ++ if scan.scanner is not None and scan.scanner !=3D "nmap": >>>> + scanner =3D scan.scanner >>>> + parts =3D [scanner] >>>> + if scan.version is not None: >>>> + parts.append(scan.version) >>>> +- parts.append(u"scan") >>>> ++ parts.append("scan") >>>> + if scan.start_date is not None: >>>> +- parts.append(u"initiated %s" % scan.start_date.strftime( >>>> ++ parts.append("initiated %s" % scan.start_date.strftime( >>>> + "%a %b %d %H:%M:%S %Y")) >>>> + if scan.args is not None: >>>> +- parts.append(u"as: %s" % scan.args) >>>> +- return u" ".join(parts) >>>> ++ parts.append("as: %s" % scan.args) >>>> ++ return " ".join(parts) >>>> + >>>> + >>>> + def print_script_result_diffs_text(title, script_results_a, script_res= ults_b, >>>> + script_result_diffs, f=3Dsys.stdout): >>>> +- table =3D Table(u"*") >>>> ++ table =3D Table("*") >>>> + for sr_diff in script_result_diffs: >>>> + sr_diff.append_to_port_table(table) >>>> + if len(table) > 0: >>>> +- print >> f >>>> ++ print(file=3Df) >>>> + if len(script_results_b) =3D=3D 0: >>>> +- print >> f, u"-%s:" % title >>>> ++ print("-%s:" % title, file=3Df) >>>> + elif len(script_results_a) =3D=3D 0: >>>> +- print >> f, u"+%s:" % title >>>> ++ print("+%s:" % title, file=3Df) >>>> + else: >>>> +- print >> f, u" %s:" % title >>>> +- print >> f, table >>>> ++ print(" %s:" % title, file=3Df) >>>> ++ print(table, file=3Df) >>>> + >>>> + >>>> + def script_result_diffs_to_dom_fragment(elem, script_results_a, >>>> +@@ -489,13 +489,13 @@ >>>> + if len(script_results_a) =3D=3D 0 and len(script_results_b) =3D=3D= 0: >>>> + return document.createDocumentFragment() >>>> + elif len(script_results_b) =3D=3D 0: >>>> +- a_elem =3D document.createElement(u"a") >>>> ++ a_elem =3D document.createElement("a") >>>> + for sr in script_results_a: >>>> + elem.appendChild(sr.to_dom_fragment(document)) >>>> + a_elem.appendChild(elem) >>>> + return a_elem >>>> + elif len(script_results_a) =3D=3D 0: >>>> +- b_elem =3D document.createElement(u"b") >>>> ++ b_elem =3D document.createElement("b") >>>> + for sr in script_results_b: >>>> + elem.appendChild(sr.to_dom_fragment(document)) >>>> + b_elem.appendChild(elem) >>>> +@@ -580,10 +580,10 @@ >>>> + banner_a =3D format_banner(self.scan_a) >>>> + banner_b =3D format_banner(self.scan_b) >>>> + if banner_a !=3D banner_b: >>>> +- print >> self.f, u"-%s" % banner_a >>>> +- print >> self.f, u"+%s" % banner_b >>>> ++ print("-%s" % banner_a, file=3Dself.f) >>>> ++ print("+%s" % banner_b, file=3Dself.f) >>>> + elif verbose: >>>> +- print >> self.f, u" %s" % banner_a >>>> ++ print(" %s" % banner_a, file=3Dself.f) >>>> + >>>> + def output_pre_scripts(self, pre_script_result_diffs): >>>> + print_script_result_diffs_text("Pre-scan script results", >>>> +@@ -596,7 +596,7 @@ >>>> + post_script_result_diffs, self.f) >>>> + >>>> + def output_host_diff(self, h_diff): >>>> +- print >> self.f >>>> ++ print(file=3Dself.f) >>>> + h_diff.print_text(self.f) >>>> + >>>> + def output_ending(self): >>>> +@@ -621,8 +621,8 @@ >>>> + >>>> + def output_beginning(self): >>>> + self.writer.startDocument() >>>> +- self.writer.startElement(u"nmapdiff", {u"version": NDIFF_XML_V= ERSION}) >>>> +- self.writer.startElement(u"scandiff", {}) >>>> ++ self.writer.startElement("nmapdiff", {"version": NDIFF_XML_VER= SION}) >>>> ++ self.writer.startElement("scandiff", {}) >>>> + >>>> + if self.nmaprun_differs(): >>>> + self.writer.frag_a( >>>> +@@ -635,7 +635,7 @@ >>>> + >>>> + def output_pre_scripts(self, pre_script_result_diffs): >>>> + if len(pre_script_result_diffs) > 0 or verbose: >>>> +- prescript_elem =3D self.document.createElement(u"prescript= ") >>>> ++ prescript_elem =3D self.document.createElement("prescript") >>>> + frag =3D script_result_diffs_to_dom_fragment( >>>> + prescript_elem, self.scan_a.pre_script_results, >>>> + self.scan_b.pre_script_results, pre_script_result_diff= s, >>>> +@@ -645,7 +645,7 @@ >>>> + >>>> + def output_post_scripts(self, post_script_result_diffs): >>>> + if len(post_script_result_diffs) > 0 or verbose: >>>> +- postscript_elem =3D self.document.createElement(u"postscri= pt") >>>> ++ postscript_elem =3D self.document.createElement("postscrip= t") >>>> + frag =3D script_result_diffs_to_dom_fragment( >>>> + postscript_elem, self.scan_a.post_script_results, >>>> + self.scan_b.post_script_results, post_script_result_di= ffs, >>>> +@@ -659,8 +659,8 @@ >>>> + frag.unlink() >>>> + >>>> + def output_ending(self): >>>> +- self.writer.endElement(u"scandiff") >>>> +- self.writer.endElement(u"nmapdiff") >>>> ++ self.writer.endElement("scandiff") >>>> ++ self.writer.endElement("nmapdiff") >>>> + self.writer.endDocument() >>>> + >>>> + >>>> +@@ -718,9 +718,9 @@ >>>> + self.cost +=3D os_cost >>>> + >>>> + extraports_a =3D tuple((count, state) >>>> +- for (state, count) in self.host_a.extraports.items()) >>>> ++ for (state, count) in list(self.host_a.extraports.item= s())) >>>> + extraports_b =3D tuple((count, state) >>>> +- for (state, count) in self.host_b.extraports.items()) >>>> ++ for (state, count) in list(self.host_b.extraports.item= s())) >>>> + if extraports_a !=3D extraports_b: >>>> + self.extraports_changed =3D True >>>> + self.cost +=3D 1 >>>> +@@ -746,69 +746,69 @@ >>>> + # Names and addresses. >>>> + if self.id_changed: >>>> + if host_a.state is not None: >>>> +- print >> f, u"-%s:" % host_a.format_name() >>>> ++ print("-%s:" % host_a.format_name(), file=3Df) >>>> + if self.host_b.state is not None: >>>> +- print >> f, u"+%s:" % host_b.format_name() >>>> ++ print("+%s:" % host_b.format_name(), file=3Df) >>>> + else: >>>> +- print >> f, u" %s:" % host_a.format_name() >>>> ++ print(" %s:" % host_a.format_name(), file=3Df) >>>> + >>>> + # State. >>>> + if self.state_changed: >>>> + if host_a.state is not None: >>>> +- print >> f, u"-Host is %s." % host_a.state >>>> ++ print("-Host is %s." % host_a.state, file=3Df) >>>> + if host_b.state is not None: >>>> +- print >> f, u"+Host is %s." % host_b.state >>>> ++ print("+Host is %s." % host_b.state, file=3Df) >>>> + elif verbose: >>>> +- print >> f, u" Host is %s." % host_b.state >>>> ++ print(" Host is %s." % host_b.state, file=3Df) >>>> + >>>> + # Extraports. >>>> + if self.extraports_changed: >>>> + if len(host_a.extraports) > 0: >>>> +- print >> f, u"-Not shown: %s" % host_a.extraports_stri= ng() >>>> ++ print("-Not shown: %s" % host_a.extraports_string(), f= ile=3Df) >>>> + if len(host_b.extraports) > 0: >>>> +- print >> f, u"+Not shown: %s" % host_b.extraports_stri= ng() >>>> ++ print("+Not shown: %s" % host_b.extraports_string(), f= ile=3Df) >>>> + elif verbose: >>>> + if len(host_a.extraports) > 0: >>>> +- print >> f, u" Not shown: %s" % host_a.extraports_stri= ng() >>>> ++ print(" Not shown: %s" % host_a.extraports_string(), f= ile=3Df) >>>> + >>>> + # Port table. >>>> +- port_table =3D Table(u"** * * *") >>>> ++ port_table =3D Table("** * * *") >>>> + if host_a.state is None: >>>> +- mark =3D u"+" >>>> ++ mark =3D "+" >>>> + elif host_b.state is None: >>>> +- mark =3D u"-" >>>> ++ mark =3D "-" >>>> + else: >>>> +- mark =3D u" " >>>> +- port_table.append((mark, u"PORT", u"STATE", u"SERVICE", u"VERS= ION")) >>>> ++ mark =3D " " >>>> ++ port_table.append((mark, "PORT", "STATE", "SERVICE", "VERSION"= )) >>>> + >>>> + for port in self.ports: >>>> + port_diff =3D self.port_diffs[port] >>>> + port_diff.append_to_port_table(port_table, host_a, host_b) >>>> + >>>> + if len(port_table) > 1: >>>> +- print >> f, port_table >>>> ++ print(port_table, file=3Df) >>>> + >>>> + # OS changes. >>>> + if self.os_changed or verbose: >>>> + if len(host_a.os) > 0: >>>> + if len(host_b.os) > 0: >>>> +- print >> f, u" OS details:" >>>> ++ print(" OS details:", file=3Df) >>>> + else: >>>> +- print >> f, u"-OS details:" >>>> ++ print("-OS details:", file=3Df) >>>> + elif len(host_b.os) > 0: >>>> +- print >> f, u"+OS details:" >>>> ++ print("+OS details:", file=3Df) >>>> + # os_diffs is a list of 5-tuples returned by >>>> + # difflib.SequenceMatcher. >>>> + for op, i1, i2, j1, j2 in self.os_diffs: >>>> + if op =3D=3D "replace" or op =3D=3D "delete": >>>> + for i in range(i1, i2): >>>> +- print >> f, "- %s" % host_a.os[i] >>>> ++ print("- %s" % host_a.os[i], file=3Df) >>>> + if op =3D=3D "replace" or op =3D=3D "insert": >>>> + for i in range(j1, j2): >>>> +- print >> f, "+ %s" % host_b.os[i] >>>> ++ print("+ %s" % host_b.os[i], file=3Df) >>>> + if op =3D=3D "equal": >>>> + for i in range(i1, i2): >>>> +- print >> f, " %s" % host_a.os[i] >>>> ++ print(" %s" % host_a.os[i], file=3Df) >>>> + >>>> + print_script_result_diffs_text("Host script results", >>>> + host_a.script_results, host_b.script_results, >>>> +@@ -819,32 +819,32 @@ >>>> + host_b =3D self.host_b >>>> + >>>> + frag =3D document.createDocumentFragment() >>>> +- hostdiff_elem =3D document.createElement(u"hostdiff") >>>> ++ hostdiff_elem =3D document.createElement("hostdiff") >>>> + frag.appendChild(hostdiff_elem) >>>> + >>>> + if host_a.state is None or host_b.state is None: >>>> + # The host is missing in one scan. Output the whole thing. >>>> + if host_a.state is not None: >>>> +- a_elem =3D document.createElement(u"a") >>>> ++ a_elem =3D document.createElement("a") >>>> + a_elem.appendChild(host_a.to_dom_fragment(document)) >>>> + hostdiff_elem.appendChild(a_elem) >>>> + elif host_b.state is not None: >>>> +- b_elem =3D document.createElement(u"b") >>>> ++ b_elem =3D document.createElement("b") >>>> + b_elem.appendChild(host_b.to_dom_fragment(document)) >>>> + hostdiff_elem.appendChild(b_elem) >>>> + return frag >>>> + >>>> +- host_elem =3D document.createElement(u"host") >>>> ++ host_elem =3D document.createElement("host") >>>> + >>>> + # State. >>>> + if host_a.state =3D=3D host_b.state: >>>> + if verbose: >>>> + host_elem.appendChild(host_a.state_to_dom_fragment(doc= ument)) >>>> + else: >>>> +- a_elem =3D document.createElement(u"a") >>>> ++ a_elem =3D document.createElement("a") >>>> + a_elem.appendChild(host_a.state_to_dom_fragment(document)) >>>> + host_elem.appendChild(a_elem) >>>> +- b_elem =3D document.createElement(u"b") >>>> ++ b_elem =3D document.createElement("b") >>>> + b_elem.appendChild(host_b.state_to_dom_fragment(document)) >>>> + host_elem.appendChild(b_elem) >>>> + >>>> +@@ -853,31 +853,31 @@ >>>> + addrset_b =3D set(host_b.addresses) >>>> + for addr in sorted(addrset_a.intersection(addrset_b)): >>>> + host_elem.appendChild(addr.to_dom_fragment(document)) >>>> +- a_elem =3D document.createElement(u"a") >>>> ++ a_elem =3D document.createElement("a") >>>> + for addr in sorted(addrset_a - addrset_b): >>>> + a_elem.appendChild(addr.to_dom_fragment(document)) >>>> + if a_elem.hasChildNodes(): >>>> + host_elem.appendChild(a_elem) >>>> +- b_elem =3D document.createElement(u"b") >>>> ++ b_elem =3D document.createElement("b") >>>> + for addr in sorted(addrset_b - addrset_a): >>>> + b_elem.appendChild(addr.to_dom_fragment(document)) >>>> + if b_elem.hasChildNodes(): >>>> + host_elem.appendChild(b_elem) >>>> + >>>> + # Host names. >>>> +- hostnames_elem =3D document.createElement(u"hostnames") >>>> ++ hostnames_elem =3D document.createElement("hostnames") >>>> + hostnameset_a =3D set(host_a.hostnames) >>>> + hostnameset_b =3D set(host_b.hostnames) >>>> + for hostname in sorted(hostnameset_a.intersection(hostnameset_= b)): >>>> + hostnames_elem.appendChild( >>>> + host_a.hostname_to_dom_fragment(document, hostname= )) >>>> +- a_elem =3D document.createElement(u"a") >>>> ++ a_elem =3D document.createElement("a") >>>> + for hostname in sorted(hostnameset_a - hostnameset_b): >>>> + a_elem.appendChild( >>>> + host_a.hostname_to_dom_fragment(document, hostname= )) >>>> + if a_elem.hasChildNodes(): >>>> + hostnames_elem.appendChild(a_elem) >>>> +- b_elem =3D document.createElement(u"b") >>>> ++ b_elem =3D document.createElement("b") >>>> + for hostname in sorted(hostnameset_b - hostnameset_a): >>>> + b_elem.appendChild( >>>> + host_b.hostname_to_dom_fragment(document, hostname= )) >>>> +@@ -886,15 +886,15 @@ >>>> + if hostnames_elem.hasChildNodes(): >>>> + host_elem.appendChild(hostnames_elem) >>>> + >>>> +- ports_elem =3D document.createElement(u"ports") >>>> ++ ports_elem =3D document.createElement("ports") >>>> + # Extraports. >>>> + if host_a.extraports =3D=3D host_b.extraports: >>>> + ports_elem.appendChild(host_a.extraports_to_dom_fragment(d= ocument)) >>>> + else: >>>> +- a_elem =3D document.createElement(u"a") >>>> ++ a_elem =3D document.createElement("a") >>>> + a_elem.appendChild(host_a.extraports_to_dom_fragment(docum= ent)) >>>> + ports_elem.appendChild(a_elem) >>>> +- b_elem =3D document.createElement(u"b") >>>> ++ b_elem =3D document.createElement("b") >>>> + b_elem.appendChild(host_b.extraports_to_dom_fragment(docum= ent)) >>>> + ports_elem.appendChild(b_elem) >>>> + # Port list. >>>> +@@ -910,18 +910,18 @@ >>>> + >>>> + # OS changes. >>>> + if self.os_changed or verbose: >>>> +- os_elem =3D document.createElement(u"os") >>>> ++ os_elem =3D document.createElement("os") >>>> + # os_diffs is a list of 5-tuples returned by >>>> + # difflib.SequenceMatcher. >>>> + for op, i1, i2, j1, j2 in self.os_diffs: >>>> + if op =3D=3D "replace" or op =3D=3D "delete": >>>> +- a_elem =3D document.createElement(u"a") >>>> ++ a_elem =3D document.createElement("a") >>>> + for i in range(i1, i2): >>>> + a_elem.appendChild(host_a.os_to_dom_fragment( >>>> + document, host_a.os[i])) >>>> + os_elem.appendChild(a_elem) >>>> + if op =3D=3D "replace" or op =3D=3D "insert": >>>> +- b_elem =3D document.createElement(u"b") >>>> ++ b_elem =3D document.createElement("b") >>>> + for i in range(j1, j2): >>>> + b_elem.appendChild(host_b.os_to_dom_fragment( >>>> + document, host_b.os[i])) >>>> +@@ -935,7 +935,7 @@ >>>> + >>>> + # Host script changes. >>>> + if len(self.script_result_diffs) > 0 or verbose: >>>> +- hostscript_elem =3D document.createElement(u"hostscript") >>>> ++ hostscript_elem =3D document.createElement("hostscript") >>>> + host_elem.appendChild(script_result_diffs_to_dom_fragment( >>>> + hostscript_elem, host_a.script_results, >>>> + host_b.script_results, self.script_result_diffs, >>>> +@@ -988,38 +988,38 @@ >>>> + self.port_b.service.version_string()] >>>> + if a_columns =3D=3D b_columns: >>>> + if verbose or self.script_result_diffs > 0: >>>> +- table.append([u" "] + a_columns) >>>> ++ table.append([" "] + a_columns) >>>> + else: >>>> + if not host_a.is_extraports(self.port_a.state): >>>> +- table.append([u"-"] + a_columns) >>>> ++ table.append(["-"] + a_columns) >>>> + if not host_b.is_extraports(self.port_b.state): >>>> +- table.append([u"+"] + b_columns) >>>> ++ table.append(["+"] + b_columns) >>>> + >>>> + for sr_diff in self.script_result_diffs: >>>> + sr_diff.append_to_port_table(table) >>>> + >>>> + def to_dom_fragment(self, document): >>>> + frag =3D document.createDocumentFragment() >>>> +- portdiff_elem =3D document.createElement(u"portdiff") >>>> ++ portdiff_elem =3D document.createElement("portdiff") >>>> + frag.appendChild(portdiff_elem) >>>> + if (self.port_a.spec =3D=3D self.port_b.spec and >>>> + self.port_a.state =3D=3D self.port_b.state): >>>> +- port_elem =3D document.createElement(u"port") >>>> +- port_elem.setAttribute(u"portid", unicode(self.port_a.spec= [0])) >>>> +- port_elem.setAttribute(u"protocol", self.port_a.spec[1]) >>>> ++ port_elem =3D document.createElement("port") >>>> ++ port_elem.setAttribute("portid", str(self.port_a.spec[0])) >>>> ++ port_elem.setAttribute("protocol", self.port_a.spec[1]) >>>> + if self.port_a.state is not None: >>>> +- state_elem =3D document.createElement(u"state") >>>> +- state_elem.setAttribute(u"state", self.port_a.state) >>>> ++ state_elem =3D document.createElement("state") >>>> ++ state_elem.setAttribute("state", self.port_a.state) >>>> + port_elem.appendChild(state_elem) >>>> + if self.port_a.service =3D=3D self.port_b.service: >>>> + port_elem.appendChild( >>>> + self.port_a.service.to_dom_fragment(document)) >>>> + else: >>>> +- a_elem =3D document.createElement(u"a") >>>> ++ a_elem =3D document.createElement("a") >>>> + a_elem.appendChild( >>>> + self.port_a.service.to_dom_fragment(document)) >>>> + port_elem.appendChild(a_elem) >>>> +- b_elem =3D document.createElement(u"b") >>>> ++ b_elem =3D document.createElement("b") >>>> + b_elem.appendChild( >>>> + self.port_b.service.to_dom_fragment(document)) >>>> + port_elem.appendChild(b_elem) >>>> +@@ -1027,10 +1027,10 @@ >>>> + port_elem.appendChild(sr_diff.to_dom_fragment(document= )) >>>> + portdiff_elem.appendChild(port_elem) >>>> + else: >>>> +- a_elem =3D document.createElement(u"a") >>>> ++ a_elem =3D document.createElement("a") >>>> + a_elem.appendChild(self.port_a.to_dom_fragment(document)) >>>> + portdiff_elem.appendChild(a_elem) >>>> +- b_elem =3D document.createElement(u"b") >>>> ++ b_elem =3D document.createElement("b") >>>> + b_elem.appendChild(self.port_b.to_dom_fragment(document)) >>>> + portdiff_elem.appendChild(b_elem) >>>> + >>>> +@@ -1085,13 +1085,13 @@ >>>> + for op, i1, i2, j1, j2 in diffs.get_opcodes(): >>>> + if op =3D=3D "replace" or op =3D=3D "delete": >>>> + for k in range(i1, i2): >>>> +- table.append_raw(u"-" + a_lines[k]) >>>> ++ table.append_raw("-" + a_lines[k]) >>>> + if op =3D=3D "replace" or op =3D=3D "insert": >>>> + for k in range(j1, j2): >>>> +- table.append_raw(u"+" + b_lines[k]) >>>> ++ table.append_raw("+" + b_lines[k]) >>>> + if op =3D=3D "equal": >>>> + for k in range(i1, i2): >>>> +- table.append_raw(u" " + a_lines[k]) >>>> ++ table.append_raw(" " + a_lines[k]) >>>> + >>>> + def to_dom_fragment(self, document): >>>> + frag =3D document.createDocumentFragment() >>>> +@@ -1101,11 +1101,11 @@ >>>> + frag.appendChild(self.sr_a.to_dom_fragment(document)) >>>> + else: >>>> + if self.sr_a is not None: >>>> +- a_elem =3D document.createElement(u"a") >>>> ++ a_elem =3D document.createElement("a") >>>> + a_elem.appendChild(self.sr_a.to_dom_fragment(document)) >>>> + frag.appendChild(a_elem) >>>> + if self.sr_b is not None: >>>> +- b_elem =3D document.createElement(u"b") >>>> ++ b_elem =3D document.createElement("b") >>>> + b_elem.appendChild(self.sr_b.to_dom_fragment(document)) >>>> + frag.appendChild(b_elem) >>>> + return frag >>>> +@@ -1119,7 +1119,7 @@ >>>> + copied to the output.""" >>>> + self.widths =3D [] >>>> + self.rows =3D [] >>>> +- self.prefix =3D u"" >>>> ++ self.prefix =3D "" >>>> + self.padding =3D [] >>>> + j =3D 0 >>>> + while j < len(template) and template[j] !=3D "*": >>>> +@@ -1144,7 +1144,7 @@ >>>> + >>>> + for i in range(len(row)): >>>> + if row[i] is None: >>>> +- s =3D u"" >>>> ++ s =3D "" >>>> + else: >>>> + s =3D str(row[i]) >>>> + if i =3D=3D len(self.widths): >>>> +@@ -1166,7 +1166,7 @@ >>>> + for row in self.rows: >>>> + parts =3D [self.prefix] >>>> + i =3D 0 >>>> +- if isinstance(row, basestring): >>>> ++ if isinstance(row, str): >>>> + # A raw string. >>>> + lines.append(row) >>>> + else: >>>> +@@ -1175,13 +1175,13 @@ >>>> + if i < len(self.padding): >>>> + parts.append(self.padding[i]) >>>> + i +=3D 1 >>>> +- lines.append(u"".join(parts).rstrip()) >>>> +- return u"\n".join(lines) >>>> ++ lines.append("".join(parts).rstrip()) >>>> ++ return "\n".join(lines) >>>> + >>>> + >>>> + def warn(str): >>>> + """Print a warning to stderr.""" >>>> +- print >> sys.stderr, str >>>> ++ print(str, file=3Dsys.stderr) >>>> + >>>> + >>>> + class NmapContentHandler(xml.sax.handler.ContentHandler): >>>> +@@ -1201,24 +1201,24 @@ >>>> + self.skip_over =3D False >>>> + >>>> + self._start_elem_handlers =3D { >>>> +- u"nmaprun": self._start_nmaprun, >>>> +- u"host": self._start_host, >>>> +- u"hosthint": self._start_hosthint, >>>> +- u"status": self._start_status, >>>> +- u"address": self._start_address, >>>> +- u"hostname": self._start_hostname, >>>> +- u"extraports": self._start_extraports, >>>> +- u"port": self._start_port, >>>> +- u"state": self._start_state, >>>> +- u"service": self._start_service, >>>> +- u"script": self._start_script, >>>> +- u"osmatch": self._start_osmatch, >>>> +- u"finished": self._start_finished, >>>> ++ "nmaprun": self._start_nmaprun, >>>> ++ "host": self._start_host, >>>> ++ "hosthint": self._start_hosthint, >>>> ++ "status": self._start_status, >>>> ++ "address": self._start_address, >>>> ++ "hostname": self._start_hostname, >>>> ++ "extraports": self._start_extraports, >>>> ++ "port": self._start_port, >>>> ++ "state": self._start_state, >>>> ++ "service": self._start_service, >>>> ++ "script": self._start_script, >>>> ++ "osmatch": self._start_osmatch, >>>> ++ "finished": self._start_finished, >>>> + } >>>> + self._end_elem_handlers =3D { >>>> +- u'host': self._end_host, >>>> +- u"hosthint": self._end_hosthint, >>>> +- u'port': self._end_port, >>>> ++ 'host': self._end_host, >>>> ++ "hosthint": self._end_hosthint, >>>> ++ 'port': self._end_port, >>>> + } >>>> + >>>> + def parent_element(self): >>>> +@@ -1248,72 +1248,72 @@ >>>> + def _start_nmaprun(self, name, attrs): >>>> + assert self.parent_element() is None >>>> + if "start" in attrs: >>>> +- start_timestamp =3D int(attrs.get(u"start")) >>>> ++ start_timestamp =3D int(attrs.get("start")) >>>> + self.scan.start_date =3D datetime.datetime.fromtimestamp( >>>> + start_timestamp) >>>> +- self.scan.scanner =3D attrs.get(u"scanner") >>>> +- self.scan.args =3D attrs.get(u"args") >>>> +- self.scan.version =3D attrs.get(u"version") >>>> ++ self.scan.scanner =3D attrs.get("scanner") >>>> ++ self.scan.args =3D attrs.get("args") >>>> ++ self.scan.version =3D attrs.get("version") >>>> + >>>> + def _start_host(self, name, attrs): >>>> +- assert self.parent_element() =3D=3D u"nmaprun" >>>> ++ assert self.parent_element() =3D=3D "nmaprun" >>>> + self.current_host =3D Host() >>>> + self.scan.hosts.append(self.current_host) >>>> + >>>> + def _start_hosthint(self, name, attrs): >>>> +- assert self.parent_element() =3D=3D u"nmaprun" >>>> ++ assert self.parent_element() =3D=3D "nmaprun" >>>> + self.skip_over =3D True >>>> + >>>> + def _start_status(self, name, attrs): >>>> +- assert self.parent_element() =3D=3D u"host" >>>> ++ assert self.parent_element() =3D=3D "host" >>>> + assert self.current_host is not None >>>> +- state =3D attrs.get(u"state") >>>> ++ state =3D attrs.get("state") >>>> + if state is None: >>>> +- warn(u'%s element of host %s is missing the "state" attrib= ute; ' >>>> +- 'assuming \unknown\.' % ( >>>> ++ warn('%s element of host %s is missing the "state" attribu= te; ' >>>> ++ 'assuming \\unknown\.' % ( >>>> + name, self.current_host.format_name())) >>>> + return >>>> + self.current_host.state =3D state >>>> + >>>> + def _start_address(self, name, attrs): >>>> +- assert self.parent_element() =3D=3D u"host" >>>> ++ assert self.parent_element() =3D=3D "host" >>>> + assert self.current_host is not None >>>> +- addr =3D attrs.get(u"addr") >>>> ++ addr =3D attrs.get("addr") >>>> + if addr is None: >>>> +- warn(u'%s element of host %s is missing the "addr" ' >>>> ++ warn('%s element of host %s is missing the "addr" ' >>>> + 'attribute; skipping.' % ( >>>> + name, self.current_host.format_name())) >>>> + return >>>> +- addrtype =3D attrs.get(u"addrtype", u"ipv4") >>>> ++ addrtype =3D attrs.get("addrtype", "ipv4") >>>> + self.current_host.add_address(Address.new(addrtype, addr)) >>>> + >>>> + def _start_hostname(self, name, attrs): >>>> +- assert self.parent_element() =3D=3D u"hostnames" >>>> ++ assert self.parent_element() =3D=3D "hostnames" >>>> + assert self.current_host is not None >>>> +- hostname =3D attrs.get(u"name") >>>> ++ hostname =3D attrs.get("name") >>>> + if hostname is None: >>>> +- warn(u'%s element of host %s is missing the "name" ' >>>> ++ warn('%s element of host %s is missing the "name" ' >>>> + 'attribute; skipping.' % ( >>>> + name, self.current_host.format_name())) >>>> + return >>>> + self.current_host.add_hostname(hostname) >>>> + >>>> + def _start_extraports(self, name, attrs): >>>> +- assert self.parent_element() =3D=3D u"ports" >>>> ++ assert self.parent_element() =3D=3D "ports" >>>> + assert self.current_host is not None >>>> +- state =3D attrs.get(u"state") >>>> ++ state =3D attrs.get("state") >>>> + if state is None: >>>> +- warn(u'%s element of host %s is missing the "state" ' >>>> ++ warn('%s element of host %s is missing the "state" ' >>>> + 'attribute; assuming "unknown".' % ( >>>> + name, self.current_host.format_name())) >>>> + state =3D None >>>> + if state in self.current_host.extraports: >>>> +- warn(u'Duplicate extraports state "%s" in host %s.' % ( >>>> ++ warn('Duplicate extraports state "%s" in host %s.' % ( >>>> + state, self.current_host.format_name())) >>>> + >>>> +- count =3D attrs.get(u"count") >>>> ++ count =3D attrs.get("count") >>>> + if count is None: >>>> +- warn(u'%s element of host %s is missing the "count" ' >>>> ++ warn('%s element of host %s is missing the "count" ' >>>> + 'attribute; assuming 0.' % ( >>>> + name, self.current_host.format_name())) >>>> + count =3D 0 >>>> +@@ -1321,99 +1321,99 @@ >>>> + try: >>>> + count =3D int(count) >>>> + except ValueError: >>>> +- warn(u"Can't convert extraports count \"%s\" " >>>> ++ warn("Can't convert extraports count \"%s\" " >>>> + "to an integer in host %s; assuming 0." % ( >>>> +- attrs[u"count"], self.current_host.format_= name())) >>>> ++ attrs["count"], self.current_host.format_n= ame())) >>>> + count =3D 0 >>>> + self.current_host.extraports[state] =3D count >>>> + >>>> + def _start_port(self, name, attrs): >>>> +- assert self.parent_element() =3D=3D u"ports" >>>> ++ assert self.parent_element() =3D=3D "ports" >>>> + assert self.current_host is not None >>>> +- portid_str =3D attrs.get(u"portid") >>>> ++ portid_str =3D attrs.get("portid") >>>> + if portid_str is None: >>>> +- warn(u'%s element of host %s missing the "portid" ' >>>> ++ warn('%s element of host %s missing the "portid" ' >>>> + 'attribute; skipping.' % ( >>>> + name, self.current_host.format_name())) >>>> + return >>>> + try: >>>> + portid =3D int(portid_str) >>>> + except ValueError: >>>> +- warn(u"Can't convert portid \"%s\" to an integer " >>>> ++ warn("Can't convert portid \"%s\" to an integer " >>>> + "in host %s; skipping port." % ( >>>> + portid_str, self.current_host.format_name())) >>>> + return >>>> +- protocol =3D attrs.get(u"protocol") >>>> ++ protocol =3D attrs.get("protocol") >>>> + if protocol is None: >>>> +- warn(u'%s element of host %s missing the "protocol" ' >>>> ++ warn('%s element of host %s missing the "protocol" ' >>>> + 'attribute; skipping.' % ( >>>> + name, self.current_host.format_name())) >>>> + return >>>> + self.current_port =3D Port((portid, protocol)) >>>> + >>>> + def _start_state(self, name, attrs): >>>> +- assert self.parent_element() =3D=3D u"port" >>>> ++ assert self.parent_element() =3D=3D "port" >>>> + assert self.current_host is not None >>>> + if self.current_port is None: >>>> + return >>>> + if "state" not in attrs: >>>> +- warn(u'%s element of port %s is missing the "state" ' >>>> ++ warn('%s element of port %s is missing the "state" ' >>>> + 'attribute; assuming "unknown".' % ( >>>> + name, self.current_port.spec_string())) >>>> + return >>>> +- self.current_port.state =3D attrs[u"state"] >>>> ++ self.current_port.state =3D attrs["state"] >>>> + self.current_host.add_port(self.current_port) >>>> + >>>> + def _start_service(self, name, attrs): >>>> +- assert self.parent_element() =3D=3D u"port" >>>> ++ assert self.parent_element() =3D=3D "port" >>>> + assert self.current_host is not None >>>> + if self.current_port is None: >>>> + return >>>> +- self.current_port.service.name =3D attrs.get(u"name") >>>> +- self.current_port.service.product =3D attrs.get(u"product") >>>> +- self.current_port.service.version =3D attrs.get(u"version") >>>> +- self.current_port.service.extrainfo =3D attrs.get(u"extrainfo") >>>> +- self.current_port.service.tunnel =3D attrs.get(u"tunnel") >>>> ++ self.current_port.service.name =3D attrs.get("name") >>>> ++ self.current_port.service.product =3D attrs.get("product") >>>> ++ self.current_port.service.version =3D attrs.get("version") >>>> ++ self.current_port.service.extrainfo =3D attrs.get("extrainfo") >>>> ++ self.current_port.service.tunnel =3D attrs.get("tunnel") >>>> + >>>> + def _start_script(self, name, attrs): >>>> + result =3D ScriptResult() >>>> +- result.id =3D attrs.get(u"id") >>>> ++ result.id =3D attrs.get("id") >>>> + if result.id is None: >>>> +- warn(u'%s element missing the "id" attribute; skipping.' %= name) >>>> ++ warn('%s element missing the "id" attribute; skipping.' % = name) >>>> + return >>>> + >>>> +- result.output =3D attrs.get(u"output") >>>> ++ result.output =3D attrs.get("output") >>>> + if result.output is None: >>>> +- warn(u'%s element missing the "output" attribute; skipping= .' >>>> ++ warn('%s element missing the "output" attribute; skipping.' >>>> + % name) >>>> + return >>>> +- if self.parent_element() =3D=3D u"prescript": >>>> ++ if self.parent_element() =3D=3D "prescript": >>>> + self.scan.pre_script_results.append(result) >>>> +- elif self.parent_element() =3D=3D u"postscript": >>>> ++ elif self.parent_element() =3D=3D "postscript": >>>> + self.scan.post_script_results.append(result) >>>> +- elif self.parent_element() =3D=3D u"hostscript": >>>> ++ elif self.parent_element() =3D=3D "hostscript": >>>> + self.current_host.script_results.append(result) >>>> +- elif self.parent_element() =3D=3D u"port": >>>> ++ elif self.parent_element() =3D=3D "port": >>>> + self.current_port.script_results.append(result) >>>> + else: >>>> +- warn(u"%s element not inside prescript, postscript, hostsc= ript, " >>>> ++ warn("%s element not inside prescript, postscript, hostscr= ipt, " >>>> + "or port element; ignoring." % name) >>>> + return >>>> + >>>> + def _start_osmatch(self, name, attrs): >>>> +- assert self.parent_element() =3D=3D u"os" >>>> ++ assert self.parent_element() =3D=3D "os" >>>> + assert self.current_host is not None >>>> + if "name" not in attrs: >>>> +- warn(u'%s element of host %s is missing the "name" ' >>>> ++ warn('%s element of host %s is missing the "name" ' >>>> + 'attribute; skipping.' % ( >>>> + name, self.current_host.format_name())) >>>> + return >>>> +- self.current_host.os.append(attrs[u"name"]) >>>> ++ self.current_host.os.append(attrs["name"]) >>>> + >>>> + def _start_finished(self, name, attrs): >>>> +- assert self.parent_element() =3D=3D u"runstats" >>>> ++ assert self.parent_element() =3D=3D "runstats" >>>> + if "time" in attrs: >>>> +- end_timestamp =3D int(attrs.get(u"time")) >>>> ++ end_timestamp =3D int(attrs.get("time")) >>>> + self.scan.end_date =3D datetime.datetime.fromtimestamp(end= _timestamp) >>>> + >>>> + def _end_host(self, name): >>>> +@@ -1435,23 +1435,23 @@ >>>> + >>>> + def frag(self, frag): >>>> + for node in frag.childNodes: >>>> +- node.writexml(self.f, newl=3Du"\n") >>>> ++ node.writexml(self.f, newl=3D"\n") >>>> + >>>> + def frag_a(self, frag): >>>> +- self.startElement(u"a", {}) >>>> ++ self.startElement("a", {}) >>>> + for node in frag.childNodes: >>>> +- node.writexml(self.f, newl=3Du"\n") >>>> +- self.endElement(u"a") >>>> ++ node.writexml(self.f, newl=3D"\n") >>>> ++ self.endElement("a") >>>> + >>>> + def frag_b(self, frag): >>>> +- self.startElement(u"b", {}) >>>> ++ self.startElement("b", {}) >>>> + for node in frag.childNodes: >>>> +- node.writexml(self.f, newl=3Du"\n") >>>> +- self.endElement(u"b") >>>> ++ node.writexml(self.f, newl=3D"\n") >>>> ++ self.endElement("b") >>>> + >>>> + >>>> + def usage(): >>>> +- print u"""\ >>>> ++ print("""\ >>>> + Usage: %s [option] FILE1 FILE2 >>>> + Compare two Nmap XML files and display a list of their differences. >>>> + Differences include host state changes, port state changes, and change= s to >>>> +@@ -1461,7 +1461,7 @@ >>>> + -v, --verbose also show hosts and ports that haven't changed. >>>> + --text display output in text format (default) >>>> + --xml display output in XML format\ >>>> +-""" % sys.argv[0] >>>> ++""" % sys.argv[0]) >>>> + >>>> + EXIT_EQUAL =3D 0 >>>> + EXIT_DIFFERENT =3D 1 >>>> +@@ -1469,8 +1469,8 @@ >>>> + >>>> + >>>> + def usage_error(msg): >>>> +- print >> sys.stderr, u"%s: %s" % (sys.argv[0], msg) >>>> +- print >> sys.stderr, u"Try '%s -h' for help." % sys.argv[0] >>>> ++ print("%s: %s" % (sys.argv[0], msg), file=3Dsys.stderr) >>>> ++ print("Try '%s -h' for help." % sys.argv[0], file=3Dsys.stderr) >>>> + sys.exit(EXIT_ERROR) >>>> + >>>> + >>>> +@@ -1481,7 +1481,7 @@ >>>> + try: >>>> + opts, input_filenames =3D getopt.gnu_getopt( >>>> + sys.argv[1:], "hv", ["help", "text", "verbose", "xml"]) >>>> +- except getopt.GetoptError, e: >>>> ++ except getopt.GetoptError as e: >>>> + usage_error(e.msg) >>>> + for o, a in opts: >>>> + if o =3D=3D "-h" or o =3D=3D "--help": >>>> +@@ -1491,15 +1491,15 @@ >>>> + verbose =3D True >>>> + elif o =3D=3D "--text": >>>> + if output_format is not None and output_format !=3D "text": >>>> +- usage_error(u"contradictory output format options.") >>>> ++ usage_error("contradictory output format options.") >>>> + output_format =3D "text" >>>> + elif o =3D=3D "--xml": >>>> + if output_format is not None and output_format !=3D "xml": >>>> +- usage_error(u"contradictory output format options.") >>>> ++ usage_error("contradictory output format options.") >>>> + output_format =3D "xml" >>>> + >>>> + if len(input_filenames) !=3D 2: >>>> +- usage_error(u"need exactly two input filenames.") >>>> ++ usage_error("need exactly two input filenames.") >>>> + >>>> + if output_format is None: >>>> + output_format =3D "text" >>>> +@@ -1512,8 +1512,8 @@ >>>> + scan_a.load_from_file(filename_a) >>>> + scan_b =3D Scan() >>>> + scan_b.load_from_file(filename_b) >>>> +- except IOError, e: >>>> +- print >> sys.stderr, u"Can't open file: %s" % str(e) >>>> ++ except IOError as e: >>>> ++ print("Can't open file: %s" % str(e), file=3Dsys.stderr) >>>> + sys.exit(EXIT_ERROR) >>>> + >>>> + if output_format =3D=3D "text": >>>> +diff -Naur nmap-7.91.orig/ndiff/setup.py nmap-7.91/ndiff/setup.py >>>> +--- nmap-7.91.orig/ndiff/setup.py 2019-12-30 07:46:34.000000000 +0100 >>>> ++++ nmap-7.91/ndiff/setup.py 2021-05-10 20:42:23.879259251 +0200 >>>> +@@ -94,7 +94,7 @@ >>>> + self.saved_prefix =3D sys.prefix >>>> + try: >>>> + distutils.command.install.install.finalize_options(self) >>>> +- except distutils.errors.DistutilsPlatformError, e: >>>> ++ except distutils.errors.DistutilsPlatformError as e: >>>> + raise distutils.errors.DistutilsPlatformError(str(e) + """ >>>> + Installing your distribution's python-dev package may solve this probl= em.""") >>>> + >>>> +@@ -227,7 +227,7 @@ >>>> + uninstaller_file.close() >>>> + >>>> + # Set exec bit for uninstaller >>>> +- mode =3D ((os.stat(uninstaller_filename)[ST_MODE]) | 0555) & 0= 7777 >>>> ++ mode =3D ((os.stat(uninstaller_filename)[ST_MODE]) | 0o555) & = 0o7777 >>>> + os.chmod(uninstaller_filename, mode) >>>> + >>>> + def write_installed_files(self): >>>> +@@ -241,7 +241,7 @@ >>>> + with open(INSTALLED_FILES_NAME, "w") as f: >>>> + for output in self.get_installed_files(): >>>> + assert "\n" not in output >>>> +- print >> f, output >>>> ++ print(output, file=3Df) >>>> + >>>> + >>>> + class my_uninstall(distutils.cmd.Command): >>>> +@@ -263,7 +263,7 @@ >>>> + # Read the list of installed files. >>>> + try: >>>> + f =3D open(INSTALLED_FILES_NAME, "r") >>>> +- except IOError, e: >>>> ++ except IOError as e: >>>> + if e.errno =3D=3D errno.ENOENT: >>>> + log.error("Couldn't open the installation record '%s'.= " >>>> + "Have you installed yet?" % INSTALLED_FILES_NA= ME) >>>> +@@ -286,7 +286,7 @@ >>>> + try: >>>> + if not self.dry_run: >>>> + os.remove(file) >>>> +- except OSError, e: >>>> ++ except OSError as e: >>>> + log.error(str(e)) >>>> + # Delete the directories. First reverse-sort the normalized pa= ths by >>>> + # length so that child directories are deleted before their pa= rents. >>>> +@@ -297,16 +297,16 @@ >>>> + log.info("Removing the directory '%s'." % dir) >>>> + if not self.dry_run: >>>> + os.rmdir(dir) >>>> +- except OSError, e: >>>> ++ except OSError as e: >>>> + if e.errno =3D=3D errno.ENOTEMPTY: >>>> + log.info("Directory '%s' not empty; not removing."= % dir) >>>> + else: >>>> + log.error(str(e)) >>>> + >>>> + >>>> +-distutils.core.setup(name=3Du"ndiff", scripts=3D[u"scripts/ndiff"], >>>> +- py_modules=3D[u"ndiff"], >>>> +- data_files=3D[(u"share/man/man1", [u"docs/ndiff.1"])], >>>> ++distutils.core.setup(name=3D"ndiff", scripts=3D["scripts/ndiff"], >>>> ++ py_modules=3D["ndiff"], >>>> ++ data_files=3D[("share/man/man1", ["docs/ndiff.1"])], >>>> + cmdclass=3D{ >>>> + "install_egg_info": null_command, >>>> + "install": checked_install, >>>> >=20 --===============2213826832317163585==--