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


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",
    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.4"


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=[]
    port=[]
    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("-")
    try:
          return rangeport,port
    except Exception as e:
        rangeport=""
        return rangeport,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("-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
if host.startswith("http://"):
    host = host.strip()
    host = host.split("http:")
    host = host[1].strip("//")
    host = host.split("/")
    host = host[0]
    for i in range(len(host)):
        if host[i] == "/":
            host = host[0:i]
if host.startswith("https://"):
    host = host.strip()
    host = host.split("https:")
    host = host[1].strip("//")
    host = host.split("/")
    host = host[0]
    for i in range(len(host)):
        if host[i] == "/":
            host = host[0:i]
if host == "None":
    host = "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 port in range(len(port_user)):
            if is_port_open(host, port_user[port]):
                print(
                    f"Open{colored('|√|','green')}{host}-->{ports[port_user[port]]}|{port_user[port]}|"
                )
            else:
                try:
                    print(
                        f"Closed{colored('|X|','red')}{host}-->{ports[port_user[port]]}|{port_user[port]}|"
                    )
                except:
                    print(f"Closed{colored('|X|','red')}{host}-->|{port_user[port]}|")
    try:
        if int(rangeports[0]) > int(rangeports[1]):
            rangesave1=rangeports[0]
            rangesave2=rangeports[1]
            rangeports[1]=rangesave1
            rangeports[0]=rangesave2
        for port in tqdm(range(int(rangeports[0]) + 1, int(rangeports[1])+1)):
            if is_port_open(host, 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}".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}".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:
        sys.exit()
if SnakeArgs().check:
    Check_network(host)
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 == "None":
        host = "localhost"

    print("".center(60, "-"))
    try:
        host = socket.gethostbyname(host)
    except Exception as e:
        try:
            hostname, list, iplist = socket.gethostbyaddr(host)
        except Exception as e:
            if host.startswith("[") and host.endswith("]"):
                host = host[1:-1]
            else:
                host = host.split("[")
                for i in range(len(host)):
                    host = host[i - 1].split("]")
                host = host[0]
            try:
                hostname, list, iplist = socket.gethostbyaddr(host)
            except Exception as e:
                print(e)
                sys.exit()

    hosting = ""
    hosting = host.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.startswith("[") and host.endswith("]"):
            host = host[1:-1]
        else:
            host = host.split("[")
            for i in range(len(host)):
                host = host[i - 1].split("]")
            host = host[0]
        ip_obj = ipaddress.ip_address(host)
        if ip_obj.version == 6:

            try:
                network = host + "/64"
                network_obj = ipaddress.ip_network(network)
            except Exception as e:
                pass
                try:
                    network = host + "/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)
        print(f"Host:{hostname[0]}")
    except:
        hostname = "Undefined"
        print(f"Host:{hostname}")
    try:
        print(f"IP:{socket.gethostbyname(host)}")
    except Exception as e:
        try:
            hostname, list, iplist = socket.gethostbyaddr(host)
            print(f"IP:{socket.gethostbyname(hostname)}")
        except:
            pass
    finally:
        print("".center(60, "-"))


if SnakeArgs().thread:
    print(f"Thread".center(60, "-"))

    for port in ports.keys():
        t = Thread(
            target=is_port_open_threads,
            kwargs={"host": host, "port": port},
        )
        threads.append(t)
        t.start()
    for t in threads:
        t.join()
if SnakeArgs().version:
    print(f"Build_{version}")
if SnakeArgs().speed:
    print(f"ProcessPoolExecutor".center(60, "-"))
    PoolProcessExecutor(host)
