import sys
import string
import argparse
import socket
import ipaddress
from concurrent.futures import ProcessPoolExecutor
from termcolor import colored
from threading import Thread
from tqdm import tqdm
from SnakeScan.Check_subnet import Check_network
from SnakeScan.PoolExecutor import PoolProcessExecutor
from SnakeScan.Get_ssl import Get_ssl


def main():
    pass


if __name__ == "__main__":
    main()
OpenPorts = []
threads = []
portsopen = 0
portsclosed = 0
Bool = True
boolsd = True
boolean = 0
ports = {
    20: "FTP-DATA",
    21: "FTP",
    22: "SSH",
    23: "Telnet",
    25: "SMTP",
    43: "WHOIS",
    53: "DNS",
    67: "DHCP",
    68: "DHCP",
    69: "TFTP",
    80: "http",
    110: "POP3",
    115: "SFTP",
    123: "NTP",
    139: "NetBios",
    143: "IMAP",
    161: "SNMP",
    179: "BGP",
    443: "HTTPS",
    445: "MICROSOFT-DS",
    465: "SSL/TLS",
    514: "SYSLOG",
    515: "PRINTER",
    554: "RTSP",
    587: "TLS/STARTTLS",
    636: "LDAPS",
    990: "FTPS",
    993: "IMAPS",
    995: "POP3S",
    1080: "SOCKS",
    1194: "OpenVPN",
    1433: "SQL Server",
    1723: "PPTP",
    2222: "SSH",
    3128: "HTTP",
    3268: "LDAP",
    3306: "MySQL",
    3389: "RDP",
    5432: "PostgreSQL",
    5900: "VNC",
    8080: "Tomcat",
    10000: "Webmin",
}
version = "1.6.9"


def is_port_open(host, port):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        try:
            s.settimeout(1)
            s.connect((host, port))
        except (OSError, socket.timeout):
            return False
        else:
            return True


def is_port_open_threads(host, port):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        try:
            s.settimeout(1)
            s.connect((host, port))
        except (OSError, socket.timeout):
            try:
                print(f"Closed{colored('|X|','red')}-->{ports.get(port)}|{port}|")
            except:
                print(f"Closed{colored('|X|','red')}-->|{port}|")
        else:
            print(f"Open{colored('|√|','green')}-->{ports.get(port)}|{port}|")


def Ports(str=""):
    rangeports = []
    rangeport = []
    port = []
    doneports = []
    str = str.split(",")
    for p in range(len(str)):
        if "-" in str[p]:
            rangeports.append(str[p])
        else:
            port.append(str[p])
    for n in range(len(port)):
        for i in string.punctuation:
            if i in port[n]:
                port[n] = port[n].replace(i, "")
    for r in range(len(rangeports)):
        rangeport = rangeports[r].split("-")
        for i in range(len(rangeport)):
            doneports.append(rangeport[i])
    try:
        return doneports, port
    except Exception as e:
        rangeport = ""
        return doneports, port
        sys.exit()


def SnakeArgs():
    parser = argparse.ArgumentParser(
        description="Snake - It's a command line module SnakeScan. Use him for more fast starting"
    )
    parser.add_argument("host", nargs="?", default="None")
    parser.add_argument(
        "-gs", "--getssl", action="store_true", help="get official ssl certificate"
    )
    parser.add_argument("-sp", "--speed", action="store_true", help="speed scan")
    parser.add_argument("-v", "--version", action="store_true", help="version")
    parser.add_argument("-i", "--info", action="store_true", help="ip info")
    parser.add_argument("-p", "--ports", help="range ports to scan host")
    parser.add_argument("-t", "--thread", action="store_true", help="fast scan")
    parser.add_argument("-ch", "--check", action="store_true", help="scan subnet")
    parser.add_argument(
        "-l",
        "--local",
        action="store_true",
        help="view you public ip - need internet",
    )
    args = parser.parse_args()
    return args


port_user = SnakeArgs().ports
host = SnakeArgs().host
host=host.split(",")
for n in range(len(host)):
    if host[n].startswith("http://"):
        host[n] = host[n].strip()
        host[n] = host[n].split("http:")
        host[n] = host[n][1].strip("//")
        host[n] = host[n].split("/")
        host[n] = host[n][0]
        for i in range(len(host)):
            if host[n][i] == "/":
                host[n] = host[n][0:i]
for n in range(len(host)):
    if host[n].startswith("https://"):
        host[n] = host[n].strip()
        host[n] = host[n].split("https:")
        host[n] = host[n][1].strip("//")
        host[n] = host[n].split("/")
        host[n] = host[n][0]
        for i in range(len(host)):
            if host[n][i] == "/":
                host[n] = host[n][0:i]
if host[0] == "None":
    host[0] = "localhost"
if SnakeArgs().ports:
    rangeports, port_user = Ports(port_user)
    for i in range(len(port_user)):
        port_user[i] = int(port_user[i])
    for n in range(len(host)):
        for port in range(len(port_user)):
            if is_port_open(host[n], port_user[port]):
                print(
                    f"Open{colored('|√|','green')}{host[n]}-->{ports[port_user[port]]}|{port_user[port]}|"
                )
            else:
                try:
                    print(
                        f"Closed{colored('|X|','red')}{host[n]}-->{ports[port_user[port]]}|{port_user[port]}|"
                    )
                except:
                    print(f"Closed{colored('|X|','red')}{host[n]}-->|{port_user[port]}|")
        try:
            first = rangeports[::2]
            second = rangeports[1::2]
            minimal = min(len(first), len(second))
            for i in range(minimal):
                if int(first[i]) > int(second[i]):
                    number = second[i]
                    second[i] = first[i]
                    first[i] = number
            for i in range(minimal):
                for port in tqdm(range(int(first[i]) + 1, int(second[i]) + 1)):
                    if is_port_open(host[n], port):
                        for name in ports:
                            if port == name:
                                OpenPorts = [port]
                                portsopen += 1
                    else:
                        portsclosed += 1
                if OpenPorts:
                    for i in OpenPorts:
                        print(f"Open{colored('|√|','green')}-->{ports[i]}|{i}|")
                    print(f"{host[n]}".center(60, "-"))
                    print(f"Closed{colored('|X|','red')}:{portsclosed}")
                    portsclosed = 0
                    print(f"Open{colored('|√|','green')}:{portsopen}")
                    portsopen = 0
                    print("-" * 60)
                else:
                    print(f"{host[n]}".center(60, "-"))
                    print(f"Closed{colored('|X|','red')}:{portsclosed}")
                    portsclosed = 0
                    print(f"Open{colored('|√|','green')}:{portsopen}")
                    portsopen = 0
                    print("-" * 60)
        except Exception as e:
            print(e)
            sys.exit()
if SnakeArgs().check:
    for n in range(len(host)):
        Check_network(host[n])
if SnakeArgs().local:
    local = ""
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        s.connect(("10.255.255.255", 1))
        local = s.getsockname()[0]
    except Exception as e:
        local = f"127.0.0.1:{e}"
    finally:
        s.close()
        print(local)
if SnakeArgs().info:
    if host[0] == "None":
        host[0] = "localhost"
    for n in range(len(host)):
        print("".center(60, "-"))
        try:
            host[n] = socket.gethostbyname(host[n])
        except Exception as e:
            try:
                hostname, list, iplist = socket.gethostbyaddr(host[n])
            except Exception as e:
                if host[n].startswith("[") and host[n].endswith("]"):
                    host[n] = host[n][1:-1]
                else:
                    host[n] = host[n].split("[")
                    for i in range(len(host)):
                        host[n] = host[n][i - 1].split("]")
                    host[n] = host[n][0]
                try:
                    hostname, list, iplist = socket.gethostbyaddr(host[n])
                except Exception as e:
                    print(e)
                    sys.exit()
    
        hosting = ""
        hosting = host[n].split(".")
        hosting[len(hosting) - 1] = "0"
        network = ""
        for i in range(len(hosting) - 1):
            network += hosting[i] + "."
        network += "0"
        network += "/24"
        hosting = network
        try:
            if host[n].startswith("[") and host[n].endswith("]"):
                host[n] = host[n][1:-1]
            else:
                host[n] = host[n].split("[")
                for i in range(len(host)):
                    host[n] = host[n][i - 1].split("]")
                host[n] = host[n][0]
            ip_obj = ipaddress.ip_address(host[n])
            if ip_obj.version == 6:
    
                try:
                    network = host[n] + "/64"
                    network_obj = ipaddress.ip_network(network)
                except Exception as e:
                    pass
                    try:
                        network = host[n] + "/128"
                        network_obj = ipaddress.ip_network(network)
                    except Exception as e:
                        pass
        except Exception as e:
            print(e)
        print(f"Type IP: {type(ip_obj)}")
        print(f"Version IP: {ip_obj.version}")
        network_obj = ipaddress.ip_network(network)
        print(f"Network: {network_obj}")
        print(f"Subnet mask: {network_obj.netmask}")
        try:
            hostname = socket.gethostbyaddr(host[n])
            print(f"Host:{hostname[0]}")
        except:
            hostname = "Undefined"
            print(f"Host:{hostname}")
        try:
            print(f"IP:{socket.gethostbyname(host[n])}")
        except Exception as e:
            try:
                hostname, list, iplist = socket.gethostbyaddr(host[n])
                print(f"IP:{socket.gethostbyname(hostname)}")
            except:
                pass
        finally:
            print("".center(60, "-"))


if SnakeArgs().thread:
    for n in range(len(host)):
        print(f"{host[n]}".center(60, "-"))
    
        for port in ports.keys():
            t = Thread(
                target=is_port_open_threads,
                kwargs={"host": host[n], "port": port},
            )
            threads.append(t)
            t.start()
        for t in threads:
            t.join()
if SnakeArgs().version:
    print(f"Build_{version}")
if SnakeArgs().speed:
    for n in range(len(host)):
        print(f"{host[n]}".center(60, "-"))
        PoolProcessExecutor(host[n])
if SnakeArgs().getssl:
    for n in range(len(host)):
        Get_ssl(host[n])
