From mboxrd@z Thu Jan 1 00:00:00 1970 From: Adolf Belka To: development@lists.ipfire.org Subject: Re: [PATCH] nmap: Update to work with python3 Date: Fri, 14 May 2021 18:09:53 +0200 Message-ID: In-Reply-To: <00d822a8-d3da-6086-e04c-d2cb5cda2c20@ipfire.org> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============4113940038824991503==" List-Id: --===============4113940038824991503== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Hi All, On 14/05/2021 17:53, Peter M=C3=BCller wrote: > Hello Adolf, hello Michael, hello *, >=20 > personally, I would vote for dropping ndiff as well, then. Then I will resubmit the nmap patch with ndiff disabled. Regards, Adolf >=20 > While a port scanning tool makes sense on a firewall to me (in certain scen= arios), I guess most > IT security folks will compare the results of such scans on a dedicated mac= hine, anyway... >=20 > Thanks, and best regards, > Peter M=C3=BCller >=20 >=20 >> Yay, we found the first blocker. >> >> 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 bei= ng updated and probably will introduce new bugs which have to be fixed by us = instead of upstream. >> >> We have two options then: >> >> a) Do we desperately need ndiff or can we just disable it? >> >> Fedora for example disabled it (https://src.fedoraproject.org/rpms/nmap/bl= ob/rawhide/f/nmap.spec#_105) >> >> So does Gentoo (https://gitweb.gentoo.org/repo/gentoo.git/tree/net-analyze= r/nmap/nmap-7.91-r2.ebuild#n106) >> >> b) Wait for upstream to merge one of the proposed ports and be happy. But = if you say they don=E2=80=99t really care much I would recommend we follow th= e crowd and go with a). >> >> -Michael >> >>> 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 ndif= f "survived" the execution >>>> of 2to3. Personally, I have not used ndiff for a long time, hence it wou= ld 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 t= he 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 a= ccepted. 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 wit= h 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 = open nmap and ncap issues the zenmap/ndiff one is at number 11. He says that = this is important but some of the other issues are harder to workaround than = zenmap/ndiff where you just need to install python2. This input was from Mar = 2021. Apparently some distros are starting to drop nmap because they no longe= r 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 inst= ead >>>>> - 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 c= an >>>>> 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-n= diff.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.ti= metuple()) >>>>> +- attrs[u"startstr"] =3D self.start_date.strftime( >>>>> ++ attrs["start"] =3D "%d" % time.mktime(self.start_date.tim= etuple()) >>>>> ++ 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.time= tuple())) >>>>> ++ "start", "%d" % time.mktime(self.start_date.timet= uple())) >>>>> + 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.extraport= s.items()] >>>>> ++ list =3D [(count, state) for (state, count) in list(self.extr= aports.items())] >>>>> + # Reverse-sort by count. >>>>> + list.sort(reverse=3DTrue) >>>>> +- return u", ".join( >>>>> +- [u"%d %s ports" % (count, state) for (count, state) i= n 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, hostn= ame)) >>>>> + 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(docume= nt)) >>>>> + 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(docume= nt)) >>>>> + 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", "tunn= el"): >>>>> + 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_re= sults_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_= VERSION}) >>>>> +- self.writer.startElement(u"scandiff", {}) >>>>> ++ self.writer.startElement("nmapdiff", {"version": NDIFF_XML_VE= RSION}) >>>>> ++ 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"prescrip= t") >>>>> ++ 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_dif= fs, >>>>> +@@ -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"postscr= ipt") >>>>> ++ postscript_elem =3D self.document.createElement("postscri= pt") >>>>> + 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_d= iffs, >>>>> +@@ -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.ite= ms())) >>>>> + extraports_b =3D tuple((count, state) >>>>> +- for (state, count) in self.host_b.extraports.items()) >>>>> ++ for (state, count) in list(self.host_b.extraports.ite= ms())) >>>>> + 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_str= ing() >>>>> ++ print("-Not shown: %s" % host_a.extraports_string(), = file=3Df) >>>>> + if len(host_b.extraports) > 0: >>>>> +- print >> f, u"+Not shown: %s" % host_b.extraports_str= ing() >>>>> ++ print("+Not shown: %s" % host_b.extraports_string(), = file=3Df) >>>>> + elif verbose: >>>>> + if len(host_a.extraports) > 0: >>>>> +- print >> f, u" Not shown: %s" % host_a.extraports_str= ing() >>>>> ++ print(" Not shown: %s" % host_a.extraports_string(), = file=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"VER= SION")) >>>>> ++ 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(do= cument)) >>>>> + 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, hostnam= e)) >>>>> +- 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, hostnam= e)) >>>>> + 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, hostnam= e)) >>>>> +@@ -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(= document)) >>>>> + else: >>>>> +- a_elem =3D document.createElement(u"a") >>>>> ++ a_elem =3D document.createElement("a") >>>>> + a_elem.appendChild(host_a.extraports_to_dom_fragment(docu= ment)) >>>>> + 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(docu= ment)) >>>>> + 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.spe= c[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(documen= t)) >>>>> + 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" attri= bute; ' >>>>> +- 'assuming \unknown\.' % ( >>>>> ++ warn('%s element of host %s is missing the "state" attrib= ute; ' >>>>> ++ '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_= name())) >>>>> + 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; skippin= g.' >>>>> ++ 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, hosts= cript, " >>>>> ++ warn("%s element not inside prescript, postscript, hostsc= ript, " >>>>> + "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(en= d_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 chang= es 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 prob= lem.""") >>>>> + >>>>> +@@ -227,7 +227,7 @@ >>>>> + uninstaller_file.close() >>>>> + >>>>> + # Set exec bit for uninstaller >>>>> +- mode =3D ((os.stat(uninstaller_filename)[ST_MODE]) | 0555) & = 07777 >>>>> ++ 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_N= AME) >>>>> +@@ -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 p= aths by >>>>> + # length so that child directories are deleted before their p= arents. >>>>> +@@ -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, >>>>> >> --===============4113940038824991503==--