Skip to content

Commit

Permalink
pep8 and pyflakesed. FIXME: pylint me
Browse files Browse the repository at this point in the history
  • Loading branch information
savon-noir committed Apr 19, 2013
1 parent b31a150 commit 2913edb
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 129 deletions.
10 changes: 5 additions & 5 deletions libnmap/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 1,12 @@
__author__ = 'Ronald Bister, Mike Boutillier'
__credits__ = [ 'Ronald Bister', 'Mike Boutillier' ]
__credits__ = ['Ronald Bister', 'Mike Boutillier']
__maintainer__ = 'Ronald Bister'
__email__ = '[email protected]'
__email__ = '[email protected]'
__license__ = 'CC-BY'
__version__ = '0.1'
__all__ = [ "NmapHost", "NmapService", "NmapParser", "NmapParserException",
"NmapReport", "NmapProcess", "DictDiffer", "NmapDiff",
"NmapDiffException", "ReportDecoder", "ReportDecoder" ]
__all__ = ["NmapHost", "NmapService", "NmapParser", "NmapParserException",
"NmapReport", "NmapProcess", "DictDiffer", "NmapDiff",
"NmapDiffException", "ReportDecoder", "ReportEncoder"]

from diff import NmapDiff, DictDiffer, NmapDiffException
from common import NmapHost, NmapService
Expand Down
63 changes: 38 additions & 25 deletions libnmap/common.py
Original file line number Diff line number Diff line change
@@ -1,8 1,9 @@
#!/usr/bin/env python
from libnmap import NmapDiff, NmapDiffException
from libnmap import NmapDiff


class NmapHost(object):
def __init__(self, starttime='', endtime='', address=None, status=None,
def __init__(self, starttime='', endtime='', address=None, status=None,
hostnames=None, services=None):
self._starttime = starttime
self._endtime = endtime
Expand All @@ -16,17 17,19 @@ def __eq__(self, other):
self.address == other.address and self.changed(other) == 0)

def __ne__(self, other):
return ((self._hostnames != other._hostnames or
return ((self._hostnames != other._hostnames or
self.address != other.address) and self.changed(other))

def __repr__(self):
return "{0}: [{1} ({2}) - {3}]".format(self.__class__.__name__,
return "{0}: [{1} ({2}) - {3}]".format(self.__class__.__name__,
self.address,
" ".join(self._hostnames),
self.status)

def __hash__(self):
return (hash(self.status) ^ hash(self.address) ^
hash(frozenset(self._services)) ^ hash(frozenset(" ".join(self._hostnames))))
hash(frozenset(self._services)) ^
hash(frozenset(" ".join(self._hostnames))))

def changed(self, other):
return len(self.diff(other).changed())
Expand Down Expand Up @@ -67,7 70,6 @@ def starttime(self):
def endtime(self):
return self._endtime


def add_hostname(self, hostname):
self._hostnames.append(hostname)

Expand All @@ -85,15 87,16 @@ def get_ports(self):
return [(p.port, p.protocol) for p in self._services]

def get_open_ports(self):
return [(p.port, p.protocol) for p in self._services if p.state == 'open']
return ([(p.port, p.protocol)
for p in self._services if p.state == 'open'])

def get_service(self, portno, protocol='tcp'):
plist = [p for p in self._services if
p.port == portno and p.protocol == protocol]
return plist.pop() if len(plist) else None

def get_service_byid(self, id):
service = [ s for s in self.service if s.id() == id ]
service = [s for s in self.service if s.id() == id]
if len(service) > 1:
raise Exception("Duplicate services found in NmapHost object")

Expand All @@ -104,19 107,21 @@ def id(self):
return self.address

def get_dict(self):
d = dict([("%s.%s" % (s.__class__.__name__, str(s.id)), hash(s)) for s in self.services ])
d.update({ 'address': self.address, 'status': self.status,
'hostnames': " ".join(self._hostnames)})
d = dict([("%s.%s" % (s.__class__.__name__,
str(s.id)), hash(s)) for s in self.services])
d.update({'address': self.address, 'status': self.status,
'hostnames': " ".join(self._hostnames)})
return d

def diff(self, other):
return NmapDiff(self, other)


class NmapService(object):
def __init__(self, portid, protocol='tcp', state=None, service=None):
try:
self._portid = int(portid or -1)
except ValueError, TypeError:
except (ValueError, TypeError):
raise
if self._portid < 0 or self._portid > 65535:
raise ValueError
Expand All @@ -126,18 131,21 @@ def __init__(self, portid, protocol='tcp', state=None, service=None):
self._service = service if service is not None else {}

def __eq__(self, other):
return (self.id == other.id and self.changed(other) == 0)
return (self.id == other.id and self.changed(other) == 0)

def __ne__(self, other):
return (self.id != other.id or self.changed(other))
return (self.id != other.id or self.changed(other))

def __repr__(self):
return "{0}: [{1} - {2}/{3} {4} ({5})]".format(self.__class__.__name__, self.state,
str(self.port), self.protocol,
self.service, self.banner)
return "{0}: [{1} {2}/{3} {4} ({5})]".format(self.__class__.__name__,
self.state,
str(self.port),
self.protocol,
self.service,
self.banner)

def __hash__(self):
return (hash(self.port) ^ hash(self.protocol) ^ hash(self.state) ^
return (hash(self.port) ^ hash(self.protocol) ^ hash(self.state) ^
hash(self.service) ^ hash(self.banner))

def changed(self, other):
Expand All @@ -159,7 167,7 @@ def protocol(self):
def state(self):
return self._state['state'] if 'state' in self._state else None

def add_state(self, state={}):
def add_state(self, state={}):
self._state = state

@property
Expand All @@ -170,19 178,24 @@ def add_service(self, service={}):
self._service = service

def open(self):
return True if self._state['state'] and self._state['state'] == 'open' else False
return (True
if self._state['state'] and self._state['state'] == 'open'
else False)

@property
def banner(self):
notrelevant = ['name', 'method', 'conf' ]
notrelevant = ['name', 'method', 'conf']
b = ''
if self._service and self._service['method'] == "probed":
b = " ".join([ k ": " self._service[k] for k in self._service.keys() if k not in notrelevant ])
b = " ".join([k ": " self._service[k]
for k in self._service.keys()
if k not in notrelevant])
return b

def get_dict(self):
return { 'id': self.id, 'port': str(self.port), 'protocol': self.protocol,
'banner': self.banner, 'service': self.service, 'state': self.state }
return ({'id': self.id, 'port': str(self.port),
'protocol': self.protocol, 'banner': self.banner,
'service': self.service, 'state': self.state})

def diff(self, other):
def diff(self, other):
return NmapDiff(self, other)
35 changes: 25 additions & 10 deletions libnmap/diff.py
Original file line number Diff line number Diff line change
@@ -1,5 1,6 @@
#!/usr/bin/env python


class DictDiffer(object):
"""
Calculate the difference between two dictionaries as:
Expand All @@ -9,30 10,44 @@ class DictDiffer(object):
(4) keys same in both and unchanged values
"""
def __init__(self, current_dict, past_dict):
self.current_dict, self.past_dict = current_dict, past_dict
self.set_current, self.set_past = set(current_dict.keys()), set(past_dict.keys())
self.current_dict = current_dict
self.past_dict = past_dict
self.set_current = set(current_dict.keys())
self.set_past = set(past_dict.keys())
self.intersect = self.set_current.intersection(self.set_past)

def added(self):
return self.set_current - self.intersect
return self.set_current - self.intersect

def removed(self):
return self.set_past - self.intersect
return self.set_past - self.intersect

def changed(self):
return set(o for o in self.intersect if self.past_dict[o] != self.current_dict[o])
return (set(o for o in self.intersect
if self.past_dict[o] != self.current_dict[o]))

def unchanged(self):
return set(o for o in self.intersect if self.past_dict[o] == self.current_dict[o])
return (set(o for o in self.intersect
if self.past_dict[o] == self.current_dict[o]))


class NmapDiff(DictDiffer):
def __init__(self, nmap_obj1, nmap_obj2):
if nmap_obj1.id != nmap_obj2.id:
raise NmapDiffException("Comparing objects with non-matching id keys")
raise NmapDiffException("Comparing objects with non-matching id")

self.object1 = nmap_obj1.get_dict()
self.object2 = nmap_obj2.get_dict()

DictDiffer.__init__(self, self.object1, self.object2)

def __repr__(self):
return ("added: [{0}] -- changed: [{1}] -- unchanged: [{2}] -- removed [{3}]".format(
self.added(), self.changed(), self.unchanged(), self.removed()))
return ('added: [{0}] -- changed: [{1}] -- \
unchanged: [{2}] -- removed [{3}]'.format(self.added(),
self.changed(),
self.unchanged(),
self.removed()))


class NmapDiffException(Exception):
def __init__(self, msg):
Expand Down
54 changes: 37 additions & 17 deletions libnmap/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 4,15 @@
from StringIO import StringIO
from libnmap import NmapHost, NmapService


class NmapParser(object):
@classmethod
def parse(cls, nmap_data=None, type='XML'):
nmap_scan = { '_nmaprun': {}, '_scaninfo': {}, '_hosts': [], '_runstats': {} }
nmap_scan = {'_nmaprun': {}, '_scaninfo': {},
'_hosts': [], '_runstats': {}}
if not nmap_data:
raise NmapParserException("No report data to parse: please provide a file")
raise NmapParserException("No report data to parse: \
please provide a file")

try:
if isinstance(nmap_data, str):
Expand All @@ -23,15 26,18 @@ def parse(cls, nmap_data=None, type='XML'):
if root.tag == 'nmaprun':
nmap_scan['_nmaprun'] = cls.__format_attributes(root)
else:
raise NmapParserException('Unpexpected data structure for XML root node')
raise NmapParserException("Unpexpected data structure \
for XML root node")
for el in root:
if el.tag == 'scaninfo':
nmap_scan['_scaninfo'] = cls.parse_scaninfo(el)
elif el.tag == 'host':
nmap_scan['_hosts'].append(cls.parse_host(el))
elif el.tag == 'runstats':
nmap_scan['_runstats'] = cls.parse_runstats(el)
#else: print "struct pparse unknown attr: %s value: %s" % (el.tag, el.get(el.tag))
#else:
# print "struct pparse unknown attr: %s value: %s" %
# (el.tag, el.get(el.tag))
return nmap_scan

@classmethod
Expand All @@ -45,7 51,8 @@ def parse_fromfile(cls, nmap_report_path, type="XML"):
r = cls.parse(fd, type)
fd.close()
else:
raise NmapParserException("Nmap data file could not be found or permissions were not set correctly")
raise NmapParserException("Nmap data file could not be found \
or permissions were not set correctly")
return r

@classmethod
Expand All @@ -60,7 67,7 @@ def parse_fromdict(cls, rdict):
hlist = []
for h in r['_hosts']:
slist = []
for s in h['__NmapHost__']['_services']:
for s in h['__NmapHost__']['_services']:
cname = '__NmapService__'
slist.append(NmapService(portid=s[cname]['_portid'],
protocol=s[cname]['_protocol'],
Expand All @@ -76,7 83,7 @@ def parse_fromdict(cls, rdict):
hlist.append(nh)
nreport['_hosts'] = hlist
return nreport

@classmethod
def parse_scaninfo(cls, scaninfo_data):
xelement = cls.__format_element(scaninfo_data)
Expand All @@ -96,7 103,9 @@ def parse_host(cls, scanhost_data):
nhost.add_service(port)
elif xh.tag in ('status', 'address'):
setattr(nhost, xh.tag, cls.__format_attributes(xh))
#else: print "struct host unknown attr: %s value: %s" % (h.tag, h.get(h.tag))
#else:
# print "struct host unknown attr: %s value: %s" %
# (h.tag, h.get(h.tag))
return nhost

@classmethod
Expand All @@ -117,7 126,9 @@ def parse_ports(cls, scanports_data):
if xservice.tag == 'port':
nport = cls.parse_port(xservice)
ports.append(nport)
#else: print "struct port unknown attr: %s value: %s" % (h.tag, h.get(h.tag))
#else:
# print "struct port unknown attr: %s value: %s" %
# (h.tag, h.get(h.tag))
return ports

@classmethod
Expand All @@ -129,15 140,17 @@ def parse_port(cls, scanport_data):

nport.add_state(cls.__format_attributes(xelement.find('state')))
if not nport.state:
raise NmapParserException("Service state is not known or could not be parsed")
raise NmapParserException("Service state is not known \
or could not be parsed")

nport.add_service(cls.__format_attributes(xelement.find('service')))
if not nport.service:
raise NmapParserException("Service name is not known or could not be parsed")
raise NmapParserException("Service name is not known \
or could not be parsed")

return nport

@classmethod
@classmethod
def parse_runstats(cls, scanrunstats_data):
xelement = cls.__format_element(scanrunstats_data)

Expand All @@ -152,7 165,8 @@ def parse_runstats(cls, scanrunstats_data):
rdict[s.tag]['down'] = s.get('down')
rdict[s.tag]['total'] = s.get('total')
else:
raise NmapParserException('Unpexpected data structure for <runstats>')
raise NmapParserException('Unpexpected data structure \
for <runstats>')

return rdict

Expand All @@ -162,27 176,33 @@ def __format_element(elt_data):
try:
xelement = ET.fromstring(elt_data)
except:
raise NmapParserException("Error while trying to instanciate XML Element from string {0}".format(elt_data))
raise NmapParserException("Error while trying \
to instanciate XML Element from \
string {0}".format(elt_data))
elif ET.iselement(elt_data):
xelement = elt_data
else:
raise NmapParserException("Error while trying to parse supplied data: unsupported format")
raise NmapParserException("Error while trying to parse supplied \
data: unsupported format")
return xelement

@staticmethod
def __format_attributes(elt_data):
r = {}
if not ET.iselement(elt_data):
raise NmapParserException("Error while trying to parse supplied data attributes: format is not XML")
raise NmapParserException("Error while trying to parse supplied \
data attributes: format is not XML")
try:
for k in elt_data.keys():
r[k] = elt_data.get(k)
if r[k] is None:
raise NmapParserException("Error while trying to build-up element attributes")
raise NmapParserException("Error while trying to build-up \
element attributes")
except:
raise
return r


class NmapParserException(Exception):
def __init__(self, msg):
self.msg = msg
Loading

0 comments on commit 2913edb

Please sign in to comment.