Python 作业#3

本次作业要求实现localProxy和remoteProxy分离式代理,需支持SOCKS5代理和HTTPS代理,且基于之前作业成果。同时,localProxy收到的每个TCP连接要单独建立代理TCP连接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作业题目

实现localProxy和remoteProxy分离式代理。

支持SOCKS5代理和HTTPS代理(基于#2作业的成果)。

localProxy收到的每个TCP连接单独建立代理TCP连接。

# localProxy.py
import asyncio
import argparse
import sys
from struct import unpack, pack


async def msg_send(reader, writer, host):
    while reader.at_eof:
        try:
            data = await reader.read(1024 * 64)
            if not data:
                writer.close()
                break
        except (ConnectionAbortedError, ConnectionResetError) as e:
            writer.close()
            print(f"{host} exit exceptionally {repr(e)}")
            break

        try:
            writer.write(data)
            await writer.drain()
        except (ConnectionAbortedError, ConnectionResetError) as e:
            writer.close()
            print(f"{host} exit exceptionally {repr(e)}")
            break

    print(f"{host} exit")


async def handle(reader, writer):
    data = await reader.read(1024 * 64)

    if (data[0] == 5):
        proxy_type = "socks5"
    else:
        proxy_type = "https"

    if (proxy_type == "socks5"):
        addr = writer.get_extra_info('peername')
        print(f"connect from {addr!r}")

        # message at least 3 bytes
        if len(data) < 3:
            print('message is too short')
            writer.close()

        writer.write(b'\x05\x00')
        await writer.drain()

        data = await reader.read(1024 * 64)

        try:
            reader_remote, writer_remote = await asyncio.open_connection(args.remote_host, args.remote_port)
            print(f"connect to remote proxy successful")
        except:
            print(f"connect to remote proxy failed")
            writer.close()
            return


        writer_remote.write(data)

        client_to_remote = msg_send(reader, writer_remote, addr[0])
        remote_to_client = msg_send(reader_remote, writer, "remote proxy")
        await asyncio.gather(client_to_remote, remote_to_client)

    else:
        addr = writer.get_extra_info('peername')
        print(f"connect from {addr!r}")

        try:
            reader_remote, writer_remote = await asyncio.open_connection(args.remote_host, args.remote_port)
            print(f"connect to remote proxy successful")
        except:
            print(f"connect to remote proxy failed")
            writer.close()
            return


        writer_remote.write(data)

        client_to_remote = msg_send(reader, writer_remote, addr[0])
        remote_to_client = msg_send(reader_remote, writer, "remote proxy")
        await asyncio.gather(client_to_remote, remote_to_client)


async def main_logic():
    server = await asyncio.start_server(handle, '127.0.0.1', args.listen_port)

    addr = server.sockets[0].getsockname()
    print(f'Serving on {addr}')

    async with server:
        await server.serve_forever()


def main():
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main_logic())


if __name__ == "__main__":
    _parser = argparse.ArgumentParser(description='local socks5 https dual proxy server')

    _parser.add_argument('--port', dest='listen_port', metavar='listen_port', required=True,
                         help='local proxy listen port')
    _parser.add_argument('--remote_host', dest='remote_host', metavar='remote_host', required=True,
                         help='remote proxy listen port')
    _parser.add_argument('--remote_port', dest='remote_port', metavar='remote_port', required=True,
                         help='remote proxy listen port')
    _parser.add_argument('--user_name', dest='user_name', metavar='user_name', required=True,
                         help='remote proxy user name')
    _parser.add_argument('--pass_word', dest='pass_word', metavar='pass_word', required=True,
                         help='remote proxy pass word')
    args = _parser.parse_args()

    main()
#remoteProxy.py
import asyncio
import argparse
import sys
import ipaddress
from struct import unpack, pack


async def msg_send(reader, writer, host):
    while reader.at_eof:
        try:
            data = await reader.read(1024 * 64)
            if not data:
                writer.close()
                break
        except (ConnectionAbortedError, ConnectionResetError) as e:
            writer.close()
            print(f"{host} exit exceptionally {repr(e)}")
            break

        try:
            writer.write(data)
            await writer.drain()
        except (ConnectionAbortedError, ConnectionResetError) as e:
            writer.close()
            print(f"{host} exit exceptionally {repr(e)}")
            break

    print(f"{host} exit")

async def handle(reader, writer):
    data = await reader.read(1024 * 64)

    if (data[0] == 5):
        proxy_type = "socks5"
    else:
        proxy_type = "https"

    if(proxy_type == "socks5"):
        addr = writer.get_extra_info('peername')
        print(f"connect from {addr!r}")

        info = unpack('!4B', data[:4])
        ver, cmd, atyp = info[0], info[1], info[3]

        # domain name
        if ver == 5 and cmd == 1 and atyp == 3:

            addr_len = unpack('!B', data[4:5])[0]
            dst_addr = data[5:addr_len + 5].decode()
            dst_port = unpack('!H', data[addr_len + 5: addr_len + 7])[0]
            print(f'destination domain name {dst_addr},destination port {dst_port}')


            try:
                reader_remote, writer_remote = await asyncio.open_connection(dst_addr, dst_port)
                writer.write(pack('!5B', 5, 0, 0, 3, addr_len) + dst_addr.encode() + pack('!H', dst_port))
                await writer.drain()
                print(f'connect to {dst_addr} successful ')
            except (TimeoutError, ConnectionRefusedError, OSError) as e:
                print(f'connect to {dst_addr} failed ')
                writer.write(pack('!5B', 5, 3, 0, 3, addr_len) + dst_addr.encode() + pack('!H', dst_port))
                await writer.drain()
                writer.close()
                return

            client_to_remote = msg_send(reader, writer_remote, addr[0])
            remote_to_client = msg_send(reader_remote, writer, dst_addr)
            await asyncio.gather(client_to_remote, remote_to_client)

        # ipv4
        elif ver == 5 and cmd == 1 and atyp == 1:

            dst_address = str(ipaddress.ip_address(data[4:8]))
            dst_port = unpack('H', data[8:10])[0]
            print(f'destination address {dst_address},destination port {dst_port}')



            try:
                reader_remote, writer_remote = await asyncio.open_connection(dst_address, dst_port)
                writer.write(pack('!8B', 5, 0, 0, 1, *unpack('!BBBB', data[4:8])) + pack('!H', dst_port))
                await writer.drain()
                print(f'connect to {dst_addr} successful ')
            except (TimeoutError, ConnectionRefusedError, OSError) as e:
                print(f'connect to {dst_addr} failed ')
                writer.write(pack('!8B', 5, 3, 0, 1, *unpack('!BBBB', data[4:8])) + pack('!H', dst_port))
                await writer.drain()
                writer.close()
                return

            client_to_remote = msg_send(reader, writer_remote, addr[0])
            remote_to_client = msg_send(reader_remote, writer, dst_address)
            await asyncio.gather(client_to_remote, remote_to_client)

        # ipv6
        elif ver == 5 and cmd == 1 and atyp == 4:
            dst_address = str(ipaddress.ip_address(data[4:20]))
            dst_port = unpack('H', data[20:22])[0]
            print(f'destination address {dst_address},destination port {dst_port}')



            try:
                reader_remote, writer_remote = await asyncio.open_connection(dst_address, dst_port)
                writer.write(pack('!20B', 5, 0, 0, 1, *unpack('!16B', data[4:20])) + pack('!H', dst_port))
                await writer.drain()
                print(f'connect to {dst_addr} successful ')
            except (TimeoutError, ConnectionRefusedError, OSError) as e:
                print(f'connect to {dst_addr} failed ')
                writer.write(pack('!20B', 5, 3, 0, 1, *unpack('!16B', data[4:20])) + pack('!H', dst_port))
                await writer.drain()
                writer.close()
                return

            client_to_remote = msg_send(reader, writer_remote, addr[0])
            remote_to_client = msg_send(reader_remote, writer, dst_address)
            await asyncio.gather(client_to_remote, remote_to_client)

        else:

            print('unsuppoted request')
            writer.close()
            return

    else:
        addr = writer.get_extra_info('peername')
        print(f"connect from {addr!r}")

        info = data.decode().split("\r\n")
        request = info[0].split(" ")

        method = request[0]
        host = request[1].split(":")[0]
        port = request[1].split(":")[1]
        ver = request[2]


        print(f'destination domain name {host},destination port {port}')


        if method.upper() == 'CONNECT':

            try:
                reader_remote, writer_remote = await asyncio.open_connection(host, port)
                reply = ver + " 200 Connection established\r\n"
                reply += "Proxy-agent: wyx\r\n\r\n"
                writer.write(reply.encode())
                await writer.drain()
                print(f'connect to {host} successful ')
            except (TimeoutError, ConnectionRefusedError) as e:
                print(f'connect to {host} failed ')
                writer.close()
                return


            client_to_remote = msg_send(reader, writer_remote, addr[0])
            remote_to_client = msg_send(reader_remote, writer, host)
            await asyncio.gather(client_to_remote, remote_to_client)


async def main_logic():
    server = await asyncio.start_server(handle, args.listen_host, args.listen_port)

    addr = server.sockets[0].getsockname()
    print(f'Serving on {addr}')

    async with server:
        await server.serve_forever()


def main():
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main_logic())

if __name__ == "__main__":
    _parser = argparse.ArgumentParser(description='remote socks5 https dual proxy server')

    _parser.add_argument('--host', dest='listen_host', metavar='listen_host', required=True,
                         help='remote proxy listen host')
    _parser.add_argument('--port', dest='listen_port', metavar='listen_port', required=True,
                         help='remote proxy listen port')

    args = _parser.parse_args()

    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值