Search code examples
python-3.xnmap

Python 3: How to generate a table from a nested list as input


So, I've got the following nested list (which I've parsed from an Nmap XML output file). It's basically a list of IP addresses, and all their open ports:

[['192.168.23.78', ['53', '88', '135', '139', '389', '445', '3389']],
 ['192.168.27.243', ['135', '139', '445', '3389', '5800', '5900']],
 ['192.168.99.164', ['135', '139', '445', '3389', '5800', '5900']],
 ['192.168.228.211', ['80']],
 ['192.168.171.74', ['135', '139', '445', '3389', '5800', '5900']]]

I would like to create a table from this data, where each first item (all IP addresses) are printed as rows. I then wish to iterate over each second item (a list of all ports per IP address), and count each unique port number. I wish this new counted unique list of ports to be printed as column headers of my table. My empty table should then roughly look like this:

                 53  80  88  135  139  389  445  3389  5800  5900
192.168.23.78
192.168.27.243
192.168.99.164
192.168.228.211
192.168.171.74

And then I wish to place X's in each correct cell for each IP address that has a given open port, like so:

                 53  80  88  135  139  389  445  3389  5800  5900
192.168.23.78    X   X       X    X    X         X
192.168.27.243               X    X         X    X     X     X
192.168.99.164               X    X         X    X     X     X
192.168.228.211      X
192.168.171.74               X    X         X    X     X     X

How would I do this with my data set?

I'm a total newbie, but I could likely figure out how to iterate over all the port numbers and get a unique port list. But I have absolutely not clue how to then plot X's on the table, in the correct cells

This is my code so far:

#!/usr/bin/env python

from pprint import pprint
import xml.etree.ElementTree as ET

def loopy(item):
    for port in host.findall('ports/port'):
        if port.get('protocol') == "tcp":
            portid = port.get('portid')
            for state in port.findall('state'):
                if state.get('state') == "open":
                    if item == "address":
                        list_addr.append(addr)
                        return
                    elif item == "portid":
                        list_portid.append(portid)

root = ET.parse('scan5.xml').getroot()
result = []
for host in root.findall('host'):
    list_portid = []
    list_addr = []
    address = host.find('address')
    addr = address.get('addr')
    loopy("address")
    loopy("portid")
    if list_addr:
        result.append([list_addr[0], list_portid])

pprint(result)

My nested list is in now result, but I have no clue how to create a table from this.

So far my code only produces the raw list:

[['10.133.23.78', ['53', '88', '135', '139', '389', '445', '3389']],
 ['10.133.27.243', ['135', '139', '445', '3389', '5800', '5900']],
 ['10.133.99.164', ['135', '139', '445', '3389', '5800', '5900']],
 ['10.135.228.211', ['80']],
 ['10.133.171.74', ['135', '139', '445', '3389', '5800', '5900']]]

Solution

  • you can use install and use prettytable package to visualise pretty table

    first pip install prettytable

    then code

    from prettytable import PrettyTable
    
    data = [['192.168.23.78', ['53', '88', '135', '139', '389', '445', '3389']],
            ['192.168.27.243', ['135', '139', '445', '3389', '5800', '5900']],
            ['192.168.99.164', ['135', '139', '445', '3389', '5800', '5900']],
            ['192.168.228.211', ['80']],
            ['192.168.171.74', ['135', '139', '445', '3389', '5800', '5900']]]
    
    ports = sorted(set([int(port) for _, open_ports in data for port in open_ports]))
    
    my_table = PrettyTable()
    header = ['ip']
    header.extend(ports)
    my_table.field_names = header
    for ip_address, open_ports in data:
        row = [ip_address]
        row.extend('X' if str(port) in open_ports else '' for port in ports)
        my_table.add_row(row)
    
    print(my_table)
    

    output

    +-----------------+----+----+----+-----+-----+-----+-----+------+------+------+
    |        ip       | 53 | 80 | 88 | 135 | 139 | 389 | 445 | 3389 | 5800 | 5900 |
    +-----------------+----+----+----+-----+-----+-----+-----+------+------+------+
    |  192.168.23.78  | X  |    | X  |  X  |  X  |  X  |  X  |  X   |      |      |
    |  192.168.27.243 |    |    |    |  X  |  X  |     |  X  |  X   |  X   |  X   |
    |  192.168.99.164 |    |    |    |  X  |  X  |     |  X  |  X   |  X   |  X   |
    | 192.168.228.211 |    | X  |    |     |     |     |     |      |      |      |
    |  192.168.171.74 |    |    |    |  X  |  X  |     |  X  |  X   |  X   |  X   |
    +-----------------+----+----+----+-----+-----+-----+-----+------+------+------+