import sys
import string
import argparse
import socket
import ipaddress
from art import tprint
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 = {
    1: "tcpmux",
    2: "compressnet",
    3: "compressnet",
    5: "rje",
    7: "Echo",
    9: "Discard",
    11: "Systat",
    13: "Daytime",
    17: "QOTD",
    18: "MSP",
    19: "Chargen",
    20: "FTP-Data",
    21: "FTP-Control",
    22: "SSH",
    23: "Telnet",
    24: "private mail",
    25: "SMTP",
    27: "nsw-fe",
    29: "msg-icp",
    31: "msg-auth",
    33: "dsp",
    35: "private printer server",
    37: "Time",
    38: "rap",
    39: "rlp",
    41: "graphics",
    42: "WINS",
    43: "Whois",
    44: "mpm-flags",
    45: "mpm",
    46: "mpm-snd",
    47: "ni-ftp",
    48: "auditd",
    49: "TACACS",
    50: "re-mail-ck",
    51: "la-maint",
    52: "xns-time",
    53: "DNS",
    54: "xns-ch",
    55: "isi-gl",
    56: "xns-auth",
    57: "private terminal",
    58: "xns-mail",
    67: "DHCP server",
    68: "DHCP client",
    69: "TFTP",
    70: "Gopher",
    79: "Finger",
    80: "HTTP",
    88: "Kerberos",
    109: "POP2",
    110: "POP3",
    111: "RPCbind",
    113: "ident",
    115: "SFTP",
    118: "SQLServ",
    119: "NNTP",
    123: "NTP",
    135: "MS-Locator",
    137: "NetBIOS-NS",
    138: "NetBIOS-DGM",
    139: "NetBIOS-SSN",
    143: "IMAP",
    161: "SNMP",
    162: "SNMP-trap",
    179: "BGP",
    194: "IRC",
    201: "AppleTalk routing maintenance",
    220: "IMAP3",
    389: "LDAP",
    443: "HTTPS",
    445: "SMB",
    465: "SMTPS",
    500: "ISAKMP",
    514: "Syslog",
    520: "RIP",
    546: "DHCPv6 client",
    547: "DHCPv6 server",
    587: "Submission",
    631: "IPP",
    636: "LDAPS",
    990: "FTPS",
    993: "IMAPS",
    995: "POP3S",
    1080: "SOCKS",
    1194: "OpenVPN",
    1433: "Microsoft SQL server",
    1521: "Oracle",
    1723: "PPTP",
    2049: "NFS",
    2222: "SSH",
    3128: "HTTP",
    3268: "LDAP",
    3306: "MySQL",
    3389: "RDP",
    5060: "SIP",
    5353: "MDNS",
    5432: "PostgreSQL",
    5900: "VNC",
    8000: "HTTP alternate",
    8080: "HTTP alternate",
    8443: "HTTPS alternate",
    8888: "HTTP alternate",
    10000: "Webmin",
}

version = "1.7.2"


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="SnakeScan - It's a command line library for scan and get information about ip."
    )
    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="Scan with using PoolProcessExecutor",
    )
    parser.add_argument("-v", "--version", action="store_true", help="Library version")
    parser.add_argument(
        "-i", "--info", action="store_true", help="IP information about host"
    )
    parser.add_argument("-p", "--ports", help="Range ports to scan host")
    parser.add_argument(
        "-t", "--thread", action="store_true", help="Scan with using Threading"
    )
    parser.add_argument("-ch", "--check", action="store_true", help="Scan ip 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"SnakeScan_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])
