Below is the file 'goatpy/nmapwrapper.py' from this revision. You can also download the file.
#!/usr/bin/python import sys import os import fcntl import select import libxml2 from goatpy import utility class Host: def __init__(self): self.addresses = [] self.hostnames = [] self.tcp_ports = [] self.udp_ports = [] def append_hostname(self, hostname): self.hostnames.append(hostname) def port_is_open(self, protocol, id, service): if protocol == "tcp": self.tcp_ports.append((int(id))) elif protocol == "udp": self.udp_ports.append((int(id))) class NmapException: def __init__(self, mesg): self._mesg = mesg def __repr__(self): return self._mesg class nmap_callback: def __init__(self, host_list): self.current_host = None self.current_port_protocol = None self.current_port_id = None self.current_port_state = None self.current_port_service = None self.host_list = host_list def startDocument(self): pass def endDocument(self): pass def startElement(self, tag, attrs): if tag == "host": if self.current_host: raise NmapException("Woah, nested host tags aren't cool.") self.current_host = Host() if not self.current_host: return if tag == "hostname": self.current_host.append_hostname(attrs['name']) elif tag == "address": self.current_host.addresses.append((attrs['addr'], attrs['addrtype'])) elif tag == "status": self.current_host.status = attrs['state'] elif tag == "port": self.current_port_protocol = attrs['protocol'] self.current_port_id = attrs['portid'] elif tag == "state": self.current_port_state = attrs['state'] elif tag == "service": self.current_port_service = attrs['name'] def endElement(self, tag): if tag == "host" and self.current_host: self.host_list.append(self.current_host) self.current_host = None elif tag == "port": if not self.current_host: raise NmapException("Port outside of host.") if self.current_port_state.startswith('open'): self.current_host.port_is_open(self.current_port_protocol, self.current_port_id, self.current_port_service) self.current_port_protocol = None self.current_port_id = None self.current_port_state = None self.current_port_service = None def nmap(command): child_stdin, child_stdout, child_stderr = os.popen3(command) utility.set_nonblocking(child_stdin) utility.set_nonblocking(child_stdout) utility.set_nonblocking(child_stderr) # ok, so we've got a stream of XML coming # in from the nmap process. We use libxml2's # progressive SAX parser to examine this XML # stream as it's coming in, and do sensible things queue = [] handler = nmap_callback(queue) ctxt = libxml2.createPushParser(handler, "", 0, "") while 1: ready = select.select([child_stdout,child_stderr],[],[]) if child_stdout in ready[0]: data = child_stdout.read() if len(data) == 0: break ctxt.parseChunk(data, len(data), 0) while len(queue): host = queue.pop() if host.status != "down": yield host if child_stderr in ready[0]: data = child_stderr.read() if len(data) == 0: break child_stdin.close() child_stdout.close() child_stderr.close() ctxt.parseChunk("", 0, 1) if __name__ == '__main__': print "Please do not press this button again." sys.exit(1)