<reponame>firefirer1983/socket-programming<filename>sockets5/socks5_rsp.py
from collections.__init__ import namedtuple
from enum import Enum
from struct import pack

from datafields import UnsignedIntegerField, RawBytesField, StringField
from sockets5.enums import Socks5RepType


class Socks5AuthRsp:
    def __new__(cls, auth_method):
        ver = 5
        auth_method = auth_method
        return pack("!BB", ver, auth_method.value)


class Socks5AddrRsp:
    def __new__(cls, atyp, addr, port):
        ver = 5
        rep = Socks5RepType.SUCCEEDED.value
        rsv = 0
        if isinstance(atyp, Enum):
            atyp = atyp.value
        addr = addr
        port = port
        if isinstance(addr, str):
            labels = [int(p) for p in addr.split(".")]
        else:
            labels = [ord(p) for p in addr.split(b".")]
        fmt_ = "!BBBB" + "B" * len(labels) + "H"
        return pack(fmt_, ver, rep, rsv, atyp, *labels, port)


AuthRsp = namedtuple("AuthRsp", "ver method")


class AddrRsp(namedtuple("AddrRsp", "ver rep rsv atyp addr port")):
    def to_bytes(self):
        return (
            pack("!BB", self.ver, self.rep)
            + self.rsv
            + self.atyp
            + self.addr
            + pack("!H", self.port)
        )


class Socks5AddrRspGen:
    def __new__(cls):
        ver = yield from UnsignedIntegerField(1)
        if ver != 5:
            return None

        rep = yield from UnsignedIntegerField(1)

        rsv = yield from RawBytesField(1)
        assert rsv == b"\x00"

        atyp = yield from RawBytesField(1)

        if atyp == b"\01":
            addr = yield from RawBytesField(4)
        elif atyp == b"\03":
            name_len = yield from UnsignedIntegerField(1)
            addr = yield from StringField(name_len)
        elif atyp == b"\04":
            addr = yield from RawBytesField(16)
        else:
            raise RuntimeError("Unknown atyp:", atyp)

        port = yield from UnsignedIntegerField(2)

        return AddrRsp(ver, rep, rsv, atyp, addr, port)


class Socks5AuthRspGen:
    def __new__(cls):
        ver = yield from UnsignedIntegerField(1)
        if ver != 5:
            return None

        method = yield from UnsignedIntegerField(1)

        return AuthRsp(ver, method)

from collections.__init__ import namedtuple
from enum import Enum
from struct import pack

from datafields import UnsignedIntegerField, RawBytesField, StringField
from sockets5.enums import Socks5RepType


class Socks5AuthRsp:
    def __new__(cls, auth_method):
        ver = 5
        auth_method = auth_method
        return pack("!BB", ver, auth_method.value)


class Socks5AddrRsp:
    def __new__(cls, atyp, addr, port):
        ver = 5
        rep = Socks5RepType.SUCCEEDED.value
        rsv = 0
        if isinstance(atyp, Enum):
            atyp = atyp.value
        addr = addr
        port = port
        if isinstance(addr, str):
            labels = [int(p) for p in addr.split(".")]
        else:
            labels = [ord(p) for p in addr.split(b".")]
        fmt_ = "!BBBB" + "B" * len(labels) + "H"
        return pack(fmt_, ver, rep, rsv, atyp, *labels, port)


AuthRsp = namedtuple("AuthRsp", "ver method")


class AddrRsp(namedtuple("AddrRsp", "ver rep rsv atyp addr port")):
    def to_bytes(self):
        return (
            pack("!BB", self.ver, self.rep)
            + self.rsv
            + self.atyp
            + self.addr
            + pack("!H", self.port)
        )


class Socks5AddrRspGen:
    def __new__(cls):
        ver = yield from UnsignedIntegerField(1)
        if ver != 5:
            return None

        rep = yield from UnsignedIntegerField(1)

        rsv = yield from RawBytesField(1)
        assert rsv == b"\x00"

        atyp = yield from RawBytesField(1)

        if atyp == b"\01":
            addr = yield from RawBytesField(4)
        elif atyp == b"\03":
            name_len = yield from UnsignedIntegerField(1)
            addr = yield from StringField(name_len)
        elif atyp == b"\04":
            addr = yield from RawBytesField(16)
        else:
            raise RuntimeError("Unknown atyp:", atyp)

        port = yield from UnsignedIntegerField(2)

        return AddrRsp(ver, rep, rsv, atyp, addr, port)


class Socks5AuthRspGen:
    def __new__(cls):
        ver = yield from UnsignedIntegerField(1)
        if ver != 5:
            return None

        method = yield from UnsignedIntegerField(1)

        return AuthRsp(ver, method)