Skip to content

Commit a13d844

Browse files
committed
added extraports support. TODO: review host.diff and serialization
1 parent f44d36a commit a13d844

4 files changed

Lines changed: 69 additions & 5 deletions

File tree

libnmap/objects/host.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,28 @@ def id(self):
495495
"""
496496
return self.address
497497

498+
@property
499+
def extraports_state(self):
500+
"""
501+
dictionnary containing state and amount of extra ports scanned
502+
for which a common state, usually, closed was discovered.
503+
504+
:return: dict with keys 'state' and 'count'
505+
"""
506+
_xtrports = self._extras['extraports']
507+
return {'state': _xtrports['state'], 'count': _xtrports['count']}
508+
509+
@property
510+
def extraports_reasons(self):
511+
"""
512+
dictionnary containing reasons why extra ports scanned
513+
for which a common state, usually, closed was discovered.
514+
515+
:return: array of dict containing keys 'state' and 'count'
516+
"""
517+
_xtrports = self._extras['extraports']
518+
return self._extras['extraports']['reasons']
519+
498520
def get_dict(self):
499521
"""
500522
Return a dict representation of the object.

libnmap/parser.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,10 @@ def _parse_xml_host(cls, scanhost_data):
252252
for hostname in cls.__parse_hostnames(xh):
253253
_hostnames.append(hostname)
254254
elif xh.tag == 'ports':
255-
for port in cls._parse_xml_ports(xh):
255+
ports_dict = cls._parse_xml_ports(xh)
256+
for port in ports_dict['ports']:
256257
_services.append(port)
258+
_host_extras['extraports'] = ports_dict['extraports']
257259
elif xh.tag == 'status':
258260
_status = cls.__format_attributes(xh)
259261
elif xh.tag == 'address':
@@ -319,15 +321,18 @@ def _parse_xml_ports(cls, scanports_data):
319321

320322
xelement = cls.__format_element(scanports_data)
321323

322-
ports = []
324+
rdict = {'ports': [], 'extraports': None}
323325
for xservice in xelement:
324326
if xservice.tag == 'port':
325327
nport = cls._parse_xml_port(xservice)
326-
ports.append(nport)
328+
rdict['ports'].append(nport)
329+
elif xservice.tag == 'extraports':
330+
extraports = cls.__parse_extraports(xservice)
331+
rdict['extraports'] = extraports
327332
#else:
328333
# print "struct port unknown attr: %s value: %s" %
329334
# (h.tag, h.get(h.tag))
330-
return ports
335+
return rdict
331336

332337
@classmethod
333338
def _parse_xml_port(cls, scanport_data):
@@ -377,6 +382,32 @@ def _parse_xml_port(cls, scanport_data):
377382
_service_extras)
378383
return nport
379384

385+
@classmethod
386+
def __parse_extraports(cls, extraports_data):
387+
"""
388+
Private method parsing the data from extra scanned ports.
389+
X extraports were in state "closed" server returned "conn-refused"
390+
tag: <extraports>
391+
392+
:param extraports_data: XML data for extraports
393+
:type extraports_data: xml.ElementTree.Element or a string
394+
395+
:return: python dict with following keys: state, count, reason
396+
"""
397+
rdict = {'state': '', 'count': '', 'reasons': []}
398+
xelement = cls.__format_element(extraports_data)
399+
extraports_dict = cls.__format_attributes(xelement)
400+
401+
if 'state' in extraports_dict:
402+
rdict['state'] = extraports_dict
403+
if 'count' in extraports_dict:
404+
rdict['count'] = extraports_dict
405+
for xelt in xelement:
406+
if xelt.tag == 'extrareasons':
407+
extrareasons_dict = cls.__format_attributes(xelt)
408+
rdict['reasons'].append(extrareasons_dict)
409+
return rdict
410+
380411
@classmethod
381412
def __parse_script(cls, script_data):
382413
"""

libnmap/test/test_host.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,16 @@ def test_host_api(self):
173173
self.assertEqual(len(h2.get_open_ports()), 3)
174174
self.assertEqual(h2.get_service(22, "tcp").state, "open")
175175

176+
def test_extra_ports(self):
177+
h1 = NmapParser.parse(host1)
178+
h2 = NmapParser.parse(host2)
179+
180+
self.assertEqual(h1.extraports_state['state'], {'count': '995', 'state': 'WILLY_WONCKA'})
181+
self.assertEqual(h1.extraports_reasons, [{'reason': 'conn-refused', 'count': '995'}])
182+
183+
self.assertEqual(h2.extraports_state['state'], {'count': '995', 'state': 'closed'})
184+
self.assertEqual(h2.extraports_reasons, [{'reason': 'conn-refused', 'count': '995'}])
185+
176186
def test_diff_host(self):
177187
h1 = NmapParser.parse(host1)
178188
h2 = NmapParser.parse(host2)

libnmap/test/test_parser.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ def test_class_parser(self):
125125
NmapParser.parse(s)
126126

127127
def test_class_ports_parser(self):
128-
plist = NmapParser.parse(self.ports_string)
128+
pdict = NmapParser.parse(self.ports_string)
129+
plist = pdict['ports']
129130
self.assertEqual(len(plist), 4)
130131
self.assertEqual(sorted([p.port for p in plist]),
131132
sorted([22, 25, 9929, 80]))

0 commit comments

Comments
 (0)