#!/usr/bin/python3
import json
import sys

class Port:
    port = 0
    state = ""
    alias = ""
    version = ""
    protocol = ""

    def __str__(self):
        return f"Port {self.port} - Version: {self.version}"

    def todict(self):
        return {
                "port":self.port,
                "alias":self.alias,
                "version":self.version,
                "protocol":self.protocol,
                }


class Host:
    ip = ""
    hostname = ""
    ports = [] # Array of Port() items

    def __str__(self):
        return f"{self.ip} [{self.hostname}]"

    def todict(self):
        return {
                "ip":self.ip,
                "hostname":self.hostname,
                "ports":[port.todict() for port in self.ports]
            }


def open_gnmap(filename):
    with open(filename, "r") as gnmap:
        lines = gnmap.read().strip().split("\n")
        lines = [l for l in lines if not l.startswith("#") and l.startswith("Host:")]
    return lines


# parse the ports part
def parse_ports(portline):
    portlist = portline.split("/,")
    outports = []
    for p in portlist:
        port = Port()
        portparts = p.split("/")
        port.port = portparts[0]
        port.state = portparts[1]
        port.protocol = portparts[2]
        port.alias = portparts[4]
        port.version = portparts[6]
        # only add 'open' ports to the list
        #if port.state == "open":
        outports.append(port)
    return outports


# list for all hosts
all_hosts = []
unique = []
def parse_line(line):

    host = Host()
    line = line.strip().replace(" ", ";").replace("\t", ";").replace("  ", "")

    # split line by space for parts
    parts = line.split(";")

    # remove the line with the status
    if parts[3] == "Status:":
        return

    # dont parse hosts twice
    ip = parts[1]
    if ip in unique:
        return

    # get hostname and remove brackets
    hostname = parts[2] if parts[2] != "()" else ""
    hostname = hostname.replace("(", "").replace(")", "")

    ports = "".join(parts[4:])
    portlist = parse_ports(ports)

    # set needed properties
    host.ip = ip
    host.hostname = hostname
    host.ports = portlist
    unique.append(ip)

    # return the crafted host
    return host


# check usage
if len(sys.argv) == 1:
    print(f"usage: {sys.argv[0]} <scan.gnmap>")
    exit(1)

# open gnmap file
lines = open_gnmap(sys.argv[1])

# parse file
for line in lines:
    outhost = parse_line(line)
    if outhost != None:
        all_hosts.append(outhost.todict())
# dump as json
print(json.dumps(all_hosts))