import socket
from termcolor import colored
from concurrent.futures import ProcessPoolExecutor

ports = {
    7: "ECHO",
    9: "DISCARD",
    13: "DAYTIME",
    17: "QOTD (Quote of the Day)",
    19: "CHARGEN (Character Generator)",
    53: "DNS (Domain Name System)",
    67: "DHCP Server",
    68: "DHCP Client",
    69: "TFTP (Trivial File Transfer Protocol)",
    111: "RPC (Remote Procedure Call)",
    123: "NTP (Network Time Protocol)",
    137: "NetBIOS Name Service",
    138: "NetBIOS Datagram Service",
    161: "SNMP (Simple Network Management Protocol)",
    162: "SNMP Trap",
    443: "QUIC (Quick UDP Internet Connections)",
    500: "ISAKMP (Internet Security Association and Key Management Protocol)",
    520: "RIP (Routing Information Protocol)",
    1434: "Microsoft SQL Server Dynamic Port Allocation",
    4500: "IPsec NAT-Traversal (NAT-T)",
    5353: "mDNS (Multicast DNS)",
    5355: "LLMNR (Link-Local Multicast Name Resolution)",
    1900: "SSDP (Simple Service Discovery Protocol)",
    3478: "STUN (Session Traversal Utilities for NAT)",
    5060: "SIP (Session Initiation Protocol)",
    5061: "SIP (Session Initiation Protocol) (TLS)",
    20777: "Garmin Training Center",
    3074: "Xbox Live",
    3479: "TURN (Traversal Using Relays around NAT)",
    4126: "Muon",
    50000: "Drone (Drone Protocol)",
    60000: "RDP (Remote Desktop Protocol) over UDP",
    5000: "fCoE (Fibre Channel over Ethernet)",
    5001: "HP OpenView Operations Agent",
    1719: "H.323 Gatekeeper RAS",
    1720: "H.323 Call Signaling",
    1812: "RADIUS authentication",
    1813: "RADIUS accounting",
    5222: "XMPP client connection",
    5269: "XMPP server connection",
}


def is_port_open_threads(host, port, timeout=1):
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.settimeout(timeout)
        message = b"Test UDP packet"
        address = (host, port)

        sock.sendto(message, address)

        try:
            data, server = sock.recvfrom(4096)
            print(f"Response received: {data.decode()} from {server}")
            print(
                f"Open{colored('[√]','green')}-->{colored(ports.get(port),'light_green')}{colored(f'|{port}|','green')} may be listening on host"
            )
        except socket.timeout:
            print(
                f"Closed{colored('[X]','red')}-->{colored(ports.get(port),'light_red')}{colored(f'|{port}|','red')} is likely closed on host"
            )
        except ConnectionRefusedError:
            print("An error occurred while scanning.")
        sock.close()
    except socket.gaierror:
        print("Error: Unable to resolve host name.")
    except socket.error as e:
        print(f"Socket error: {e}")


def PoolExecutorUDP(host):
    with ProcessPoolExecutor(max_workers=None) as executor:
        try:
            for port in ports.keys():
                future = executor.submit(is_port_open_threads, host, port)

        except Exception as e:
            print(e)
