# nohup python3 proxy.py >/dev/null 2>&1 &

import socket
import threading

HOST = "0.0.0.0"
PORT = 1080


def handle_client(client):
    try:
        # 1. handshake
        version, nmethods = client.recv(2)
        client.recv(nmethods)
        client.sendall(b"\x05\x00")

        # 2. request
        ver, cmd, _, atype = client.recv(4)

        if atype == 1:  # IPv4
            addr = socket.inet_ntoa(client.recv(4))
        elif atype == 3:  # domain
            length = client.recv(1)[0]
            addr = client.recv(length).decode()
        else:
            client.close()
            return

        port = int.from_bytes(client.recv(2), 'big')

        # 3. connect to target
        remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        remote.connect((addr, port))

        client.sendall(b"\x05\x00\x00\x01" + socket.inet_aton("0.0.0.0") + b"\x00\x00")

        # 4. relay
        def forward(src, dst):
            try:
                while True:
                    data = src.recv(4096)
                    if not data:
                        break
                    dst.sendall(data)
            except:
                pass

        threading.Thread(target=forward, args=(client, remote)).start()
        threading.Thread(target=forward, args=(remote, client)).start()

    except:
        client.close()


def main():
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((HOST, PORT))
    server.listen(100)

    print(f"SOCKS5 proxy running on {HOST}:{PORT}")

    while True:
        client, _ = server.accept()
        threading.Thread(target=handle_client, args=(client,)).start()


if __name__ == "__main__":
    main()