#!/usr/bin/env bash

print_usage_and_exit() {
    echo "Usage: $0 <path_to_gnmap_file>"
    echo "Please provide exactly one argument: a path to an existing Nmap greppable (.gnmap) file."
    exit 1
}

# Check if exactly one argument is provided
if [ $# -ne 1 ]; then
    print_usage_and_exit
fi

# Check if the provided argument is a path to an existing file
if [ ! -f "$1" ]; then
    echo "Error: The file '$1' does not exist."
    print_usage_and_exit
fi

# Add header to TSV file
echo -e "IP\tHostname\tPort\tService\tBanner"

# Process the gnmap file
# sed command explanation:
# -n: suppress automatic printing of pattern space
# s/: start substitution command
# ^Host: : match lines starting with "Host: "
# \(.*\) (): capture IP address
# .*Ports: : match everything up to "Ports: "
# \(.*\): capture all port information
# /\1\t\2/p: replace with captured IP and port info, separated by a tab, then print
sed -n 's/^Host: \(.*\) ().*Ports: \(.*\)/\1\t\2/p' "$1" | \
awk -F'\t' '{
    # Extract IP address from the first field
    ip = $1
    # Remove parentheses from IP if present
    gsub(/[()]/, "", ip)

    # Split the second field (ports info) into an array
    split($2, ports, ", ")

    # Process each port
    for (i in ports) {
        # Split port info into an array
        split(ports[i], p, "/")
        
        # Extract port number
        port = p[1]
        
        # Extract service name
        service = p[5]
        
        # Extract banner information
        banner = p[7]
        
        # Concatenate additional banner info if present
        for (j=8; j<=length(p); j++) {
            if (p[j] != "") banner = banner " " p[j]
        }
        
        # Remove leading and trailing spaces from banner
        gsub(/^ /, "", banner)
        gsub(/ $/, "", banner)
        
        # Replace "ssl|http" service with "https"
        if (service == "ssl|http") service = "https"
        
        # Remove question marks from service name
        gsub(/\?/, "", service)
        
        # Replace empty service with "null"
        if (service == "") service = "null"
        
        # Replace empty or space-only banner with "null"
        if (banner == "" || banner == " ") banner = "null"
        
        # Print the formatted output
        printf "%s\tnull\t%s\t%s\t%s\n", ip, port, service, banner
    }
}' | sort -n -k3,3 > nmapdata.csv