Beispiel #1
0
async def tcp_forward_server(conns, server, forward_hosts, speed_limiter):
    while True:
        conn = await server.accept()
        conn_ip, forward_address, subnet = conn.address[0], None, None
        for a, s in forward_hosts:
            if is_subnet(conn_ip, s):
                forward_address, subnet = a, s
                break

        if not forward_address:
            conn.close()
            logging.info("tcp forward subnet fail %s:%d", conn.address[0],
                         conn.address[1])
            return

        status = {
            "recv_len": 0,
            "send_len": 0,
            "last_time": time.time(),
            "check_recv_len": 0,
            "check_send_len": 0,
            "speed_limiter": speed_limiter
        }
        sevent.current().call_async(tcp_forward, conns, conn, forward_address,
                                    subnet, status)
        conns[id(conn)] = (conn, status)
Beispiel #2
0
    async def loop_global_speed(self):
        try:
            current_timestamp = time.time()
            await sevent.current().sleep(0.1)
            while self.buffers:
                try:
                    avg_speed = int(self.global_speed / len(self.buffers))
                    max_speed, over_speed = min(avg_speed, self.speed), 0
                    speed_buffers = []
                    for _, (data, callback) in self.buffers.items():
                        dl = len(data)
                        if max_speed > dl:
                            speed_buffers.append((data, dl, dl, callback))
                            over_speed += avg_speed - dl
                        else:
                            speed_buffers.append(
                                (data, dl, max_speed, callback))
                            over_speed += avg_speed - max_speed

                    for data, dl, speed, callback in speed_buffers:
                        if over_speed > 0 and dl > speed and speed < self.speed:
                            can_speed = min(
                                min(dl, self.speed) - speed, over_speed)
                            speed += can_speed
                            over_speed -= can_speed
                        sevent.current().add_async(callback, data, speed)
                    self.current_speed = over_speed
                finally:
                    now = time.time()
                    sleep_time = 0.2 - (now - current_timestamp)
                    current_timestamp = now
                    await sevent.current().sleep(sleep_time)
        finally:
            self.current_speed = self.global_speed
            self.is_running = False
Beispiel #3
0
async def tcp_forward_servers(servers, timeout, speed, global_speed):
    conns, speed_limiter = {}, (SpeedLimiter(speed, global_speed)
                                if speed or global_speed else None)
    for server, forward_hosts in servers:
        sevent.current().call_async(tcp_forward_server, conns, server,
                                    forward_hosts, speed_limiter)
    await check_timeout(conns, timeout)
Beispiel #4
0
    def run_check():
        while True:
            try:
                now = time.time()
                for conn in tuple(conn_status["remote_conn"]):
                    if not hasattr(conn, "_authed_time"):
                        if now - conn._connected_time >= 30:
                            sevent.current().add_async_safe(conn.close)
                    elif now - conn._authed_time >= 180:
                        sevent.current().add_async_safe(conn.close)

                for conn in tuple(conn_status["local_conn"]):
                    if now - conn._connected_time >= 180:
                        sevent.current().add_async_safe(conn.close)

                for conn_id, (conn, pconn, status) in list(conns.items()):
                    if status['check_recv_len'] != status['recv_len'] or status[
                            'check_send_len'] != status['send_len']:
                        status["check_recv_len"] = status["recv_len"]
                        status["check_send_len"] = status["send_len"]
                        status['last_time'] = now
                        continue

                    if now - status['last_time'] >= timeout:
                        sevent.current().add_async_safe(conn.close)
                        sevent.current().add_async(pconn.close)
                        conns.pop(conn_id, None)
            finally:
                time.sleep(min(float(timeout) / 2.0, 30))
Beispiel #5
0
 async def loop(self):
     try:
         while self.queues:
             now = time.time()
             timeout_time, data, data_len, callback = self.queues.popleft()
             if timeout_time > now:
                 await sevent.current().sleep(timeout_time - now)
             sevent.current().add_async(callback, data, data_len)
     finally:
         self.is_running = False
Beispiel #6
0
async def server_run_server(server, forward_address, key, proxy_type, conns,
                            status, handle):
    while True:
        try:
            conn = await server.accept()
            sevent.current().call_async(handle, conn, forward_address, key,
                                        proxy_type, conns, status)
        except sevent.errors.SocketClosed as e:
            sevent.current().call_async(sevent.current().stop)
            raise e
Beispiel #7
0
def main(argv):
    parser = argparse.ArgumentParser(description='iptables redirect forward to http or socks5 uplink proxy')
    parser.add_argument('-b', dest='bind', default="0.0.0.0", help='local bind host (default: 0.0.0.0)')
    parser.add_argument('-p', dest='port', default=8088, type=int, help='local bind port (default: 8088)')
    parser.add_argument('-t', dest='timeout', default=7200, type=int, help='no read/write timeout (default: 7200)')
    parser.add_argument('-T', dest='proxy_type', default="http", choices=("http", "socks5"), help='proxy type (default: http)')
    parser.add_argument('-P', dest='proxy_host', default="127.0.0.1:8088", help='proxy host, accept format [proxy_host:proxy_port]  (default: 127.0.0.1:8088)')
    args = parser.parse_args(args=argv)
    config_signal()
    server = create_server((args.bind, args.port))
    logging.info("listen server at %s:%d", args.bind, args.port)
    sevent.current().call_async(tcp_accept, server, args)
Beispiel #8
0
async def tcp_accept(server, timeout):
    conns = {}
    sevent.current().call_async(check_timeout, conns, timeout)
    while True:
        conn = await server.accept()
        status = {
            "recv_len": 0,
            "send_len": 0,
            "last_time": time.time(),
            "check_recv_len": 0,
            "check_send_len": 0
        }
        sevent.current().call_async(tcp_proxy, conns, conn, status)
        conns[id(conn)] = (conn, status)
Beispiel #9
0
 def __(data):
     data_len = max(len(data) - status[key], 0)
     if delayer.delay:
         delayer.queues.append(
             (time.time() + delayer.delay, data, data_len, delay_write))
     else:
         delayer.queues.append(
             (time.time() +
              random.randint(*delayer.rdelays) / 1000000.0, data,
              data_len, delay_write))
     status[key] += data_len
     if delayer.is_running:
         return
     delayer.is_running = True
     sevent.current().call_async(delayer.loop)
Beispiel #10
0
 async def loop_speed(self):
     try:
         current_timestamp = time.time()
         await sevent.current().sleep(0.1)
         while self.buffers:
             try:
                 for _, (data, callback) in list(self.buffers.items()):
                     sevent.current().add_async(callback, data, self.speed)
             finally:
                 now = time.time()
                 sleep_time = 0.2 - (now - current_timestamp)
                 current_timestamp = now
                 await sevent.current().sleep(sleep_time)
     finally:
         self.is_running = False
Beispiel #11
0
    def run_check():
        while True:
            try:
                now = time.time()
                for conn_id, (conn, status) in list(conns.items()):
                    if status['check_recv_len'] != status['recv_len'] or status['check_send_len'] != status['send_len']:
                        status["check_recv_len"] = status["recv_len"]
                        status["check_send_len"] = status["send_len"]
                        status['last_time'] = now
                        continue

                    if now - status['last_time'] >= timeout:
                        sevent.current().add_async_safe(conn.close)
                        conns.pop(conn_id, None)
            finally:
                time.sleep(min(float(timeout) / 2.0, 30))
Beispiel #12
0
async def client_run_server(server, remote_address, key, proxy_type, conns):
    while True:
        try:
            conn = await server.accept()
            status = {
                "recv_len": 0,
                "send_len": 0,
                "last_time": time.time(),
                "check_recv_len": 0,
                "check_send_len": 0
            }
            sevent.current().call_async(client_handle_local_connect, conn,
                                        remote_address, key, proxy_type, conns,
                                        status)
            conns[id(conn)] = (conn, conn, status)
        except sevent.errors.SocketClosed as e:
            sevent.current().call_async(sevent.current().stop)
            raise e
Beispiel #13
0
async def tcp_accept(server, args):
    proxy_info = args.proxy_host.split(":")
    if len(proxy_info) == 1:
        if not proxy_info[0].isdigit():
            proxy_host, proxy_port = proxy_info[0], 8088
        else:
            proxy_host, proxy_port = "127.0.0.1", int(proxy_info[0])
    else:
        proxy_host, proxy_port = proxy_info[0], int(proxy_info[1])

    logging.info("use %s proxy %s:%d", args.proxy_type, proxy_host, proxy_port)
    conns = {}
    sevent.current().call_async(check_timeout, conns, args.timeout)
    while True:
        conn = await server.accept()
        status = {"recv_len": 0, "send_len": 0, "last_time": time.time(), "check_recv_len": 0, "check_send_len": 0}
        sevent.current().call_async(tcp_proxy, conns, conn, args.proxy_type, proxy_host, proxy_port, status)
        conns[id(conn)] = (conn, status)
Beispiel #14
0
def main(argv):
    parser = argparse.ArgumentParser(
        description='simple http and socks5 proxy server')
    parser.add_argument('-b',
                        dest='bind',
                        default="0.0.0.0",
                        help='local bind host (default: 0.0.0.0)')
    parser.add_argument('-p',
                        dest='port',
                        default=8088,
                        type=int,
                        help='local bind port (default: 8088)')
    parser.add_argument('-t',
                        dest='timeout',
                        default=7200,
                        type=int,
                        help='no read/write timeout (default: 7200)')
    args = parser.parse_args(args=argv)
    config_signal()
    logging.info("listen server at %s:%d", args.bind, args.port)
    server = create_server((args.bind, args.port))
    sevent.current().call_async(tcp_accept, server, args.timeout)
Beispiel #15
0
async def client_run_connect(remote_address, forward_address, key, conns,
                             status):
    while True:
        start_time = time.time()
        try:
            conn = create_socket(remote_address)
            await conn.connectof(remote_address)
            sign_key = gen_sign_key(key)
            await conn.send(struct.pack("!BB", 1, len(sign_key)) + sign_key)
            connect_type = (await conn.recv(1)).read(1)
            if connect_type == b'\x01':
                current_forward_address = await read_forward_address(conn)
            else:
                current_forward_address = forward_address
            forward_status = {
                "recv_len": 0,
                "send_len": 0,
                "last_time": time.time(),
                "check_recv_len": 0,
                "check_send_len": 0
            }
            sevent.current().call_async(tcp_forward, conn,
                                        current_forward_address, conns,
                                        forward_status)
        except sevent.errors.SocketClosed as e:
            logging.info("connect error %s:%d %s", remote_address[0],
                         remote_address[1], e)
            if time.time() - start_time < 5:
                await sevent.sleep(5)
        except (sevent.errors.ResolveError, ConnectionRefusedError) as e:
            logging.info("connect error %s:%d %s", remote_address[0],
                         remote_address[1], e)
            await sevent.sleep(5)
        except Exception as e:
            sevent.current().call_async(sevent.current().stop)
            raise e
Beispiel #16
0
async def tcp_accept(server, args):
    proxy_info = args.proxy_host.split(":")
    if len(proxy_info) == 1:
        if not proxy_info[0].isdigit():
            proxy_host, proxy_port = proxy_info[0], 8088
        else:
            proxy_host, proxy_port = "127.0.0.1", int(proxy_info[0])
    else:
        proxy_host, proxy_port = proxy_info[0], int(proxy_info[1])
    noproxy_hosts = []
    for noproxy_host in args.noproxy_hosts.split(","):
        if "*" in noproxy_host and "*" != noproxy_host:
            noproxy_hosts.append(re.compile(noproxy_host.replace(".", "\.").replace("*", ".+?")))
        else:
            noproxy_hosts.append(noproxy_host)

    logging.info("use %s proxy %s:%d", args.proxy_type, proxy_host, proxy_port)
    conns = {}
    sevent.current().call_async(check_timeout, conns, args.timeout)
    while True:
        conn = await server.accept()
        status = {"recv_len": 0, "send_len": 0, "last_time": time.time(), "check_recv_len": 0, "check_send_len": 0}
        sevent.current().call_async(tcp_proxy, conns, conn, args.proxy_type, proxy_host, proxy_port, noproxy_hosts, status)
        conns[id(conn)] = (conn, status)
Beispiel #17
0
    def speed_write(data, speed):
        dl = len(data)
        if dl > speed:
            if speed <= 0:
                if speed_limiter.current_speed <= 0:
                    return
                speed = min(speed_limiter.current_speed, speed_limiter.speed)
                if dl > speed:
                    status[key] += buffer.fetch(data, speed)
                    speed_limiter.current_speed -= speed
                else:
                    status[key] += dl
                    speed_limiter.current_speed -= dl
            else:
                status[key] += buffer.fetch(data, speed)
            try:
                return origin_write(buffer)
            except sevent.tcp.SocketClosed:
                speed_limiter.buffers.pop(conn_id, None)
                if status[end_key]:
                    status[end_key] = False
                    sevent.current().add_async(origin_end)
                return False

        if not data:
            speed_limiter.buffers.pop(conn_id, None)
            if status[end_key]:
                status[end_key] = False
                sevent.current().add_async(origin_end)
            return True

        status[key] += dl
        try:
            return origin_write(data)
        except sevent.tcp.SocketClosed:
            return False
Beispiel #18
0
async def server_handle_remote_connect(conn, forward_address, key, proxy_type,
                                       conns, status):
    setattr(conn, "_connected_time", time.time())

    def on_close(conn):
        if conn not in status["remote_conn"]:
            return
        status["remote_conn"].remove(conn)
        logging.info("remote conn waited close %s:%d", conn.address[0],
                     conn.address[1])

    status["remote_conn"].append(conn)
    conn.on_close(on_close)
    try:
        connect_type, sign_key_len = struct.unpack("!BB",
                                                   (await
                                                    conn.recv(2)).read(2))
        sign_key = (await conn.recv(sign_key_len)
                    ).read(sign_key_len) if sign_key_len > 0 else b''
    except sevent.errors.SocketClosed:
        return
    if not check_sign_key(key, sign_key):
        await conn.closeof()
        logging.info("remote conn auth fail %s:%d %s", conn.address[0],
                     conn.address[1], sign_key)
        return

    if connect_type == 1:
        setattr(conn, "_authed_time", time.time())
        if status["local_conn"]:
            forward_status = {
                "recv_len": 0,
                "send_len": 0,
                "last_time": time.time(),
                "check_recv_len": 0,
                "check_send_len": 0
            }
            local_conn = status["local_conn"].pop(0)
            sevent.go(reverse_port_forward, conn, local_conn, forward_status,
                      local_conn._connected_forward_address)
            conns[id(conn)] = (conn, local_conn, forward_status)
            if conn not in status["remote_conn"]:
                return
            status["remote_conn"].remove(conn)
            return
        logging.info("remote conn waiting %s:%d", conn.address[0],
                     conn.address[1])
        return

    if connect_type == 2 or connect_type == 3:
        try:
            if connect_type == 3:
                forward_address = await read_forward_address(conn)
            await conn.send(b'\x00')
            forward_status = {
                "recv_len": 0,
                "send_len": 0,
                "last_time": time.time(),
                "check_recv_len": 0,
                "check_send_len": 0
            }
            sevent.current().call_async(tcp_forward, conn, forward_address,
                                        conns, forward_status)
        except sevent.errors.SocketClosed:
            pass
        except Exception as e:
            logging.info("tcp forward error %s:%d -> %s:%d %s\r%s",
                         conn.address[0], conn.address[1], forward_address[0],
                         forward_address[1], e, traceback.format_exc())
        return

    await conn.closeof()
    logging.info("remote conn unsupport connect type %s:%d %s",
                 conn.address[0], conn.address[1], key)
Beispiel #19
0
def main(argv):
    parser = argparse.ArgumentParser(description='tcp reverse port forward')
    parser.add_argument('-c',
                        dest='is_client_mode',
                        nargs='?',
                        const=True,
                        default=False,
                        type=bool,
                        help='is client mode (defualt: False)')
    parser.add_argument('-k',
                        dest='key',
                        default='',
                        type=str,
                        help='auth key (defualt: "")')
    parser.add_argument(
        '-b',
        dest='bind_host',
        default="0.0.0.0",
        help='server and client mode local bind host (default: 0.0.0.0)')
    parser.add_argument(
        '-p',
        dest='bind_port',
        default=0,
        type=int,
        help='server and client mode local bind port (default: 8089)')
    parser.add_argument(
        '-r',
        dest='listen_host',
        default="0.0.0.0",
        help='server mode reverse server listen host (default: 0.0.0.0)')
    parser.add_argument(
        '-l',
        dest='listen_port',
        default=8088,
        type=int,
        help='server mode reverse server listen port (default: 8088)')
    parser.add_argument(
        '-H',
        dest='connect_host',
        default="127.0.0.1",
        help=
        'client mode reverse client connect server host (default: 127.0.0.1)')
    parser.add_argument(
        '-P',
        dest='connect_port',
        default=8088,
        type=int,
        help='client mode reverse client connect server port (default: 8088)')
    parser.add_argument(
        '-f',
        dest='forward_host',
        default="",
        help=
        'server and client mode forward host , accept format [remote_host:remote_port] (default: )'
    )
    parser.add_argument(
        '-T',
        dest='proxy_type',
        default="",
        choices=("raw", "http", "socks5", "redirect"),
        help='server and client mode local listen proxy type (default: raw)')
    parser.add_argument('-t',
                        dest='timeout',
                        default=7200,
                        type=int,
                        help='no read/write timeout (default: 7200)')
    args = parser.parse_args(args=argv)
    config_signal()

    if not args.forward_host:
        forward_address = None
    else:
        forward_info = args.forward_host.split(":")
        if len(forward_info) == 1:
            if not forward_info[0].isdigit():
                forward_address = (forward_info[0], 8088)
            else:
                forward_address = ("127.0.0.1", int(forward_info[0]))
        else:
            forward_address = (forward_info[0], int(forward_info[1]))

    if not args.is_client_mode:
        remote_server = create_server((args.listen_host, args.listen_port))
        local_server = create_server((args.bind_host, args.bind_port or 8089))
        logging.info("listen %s %d -> %s:%d", args.bind_host, args.bind_port
                     or 8089, args.listen_host, args.listen_port)

        sevent.instance().call_async(
            server_run_server, remote_server,
            forward_address if forward_address else ("127.0.0.1", 80),
            sevent.utils.ensure_bytes(args.key), args.proxy_type, conns,
            status, server_handle_remote_connect)
        sevent.instance().call_async(server_run_server, local_server,
                                     forward_address,
                                     sevent.utils.ensure_bytes(args.key),
                                     args.proxy_type, conns, status,
                                     server_handle_local_connect)
    else:
        if args.bind_port:
            local_server = create_server((args.bind_host, args.bind_port))
            logging.info("listen %s %d", args.bind_host, args.bind_port)
            sevent.instance().call_async(
                client_run_server, local_server,
                (args.connect_host, args.connect_port),
                sevent.utils.ensure_bytes(args.key), args.proxy_type, conns)

        logging.info("connect %s:%d -> %s", args.connect_host,
                     args.connect_port, forward_address)
        sevent.instance().call_async(
            client_run_connect, (args.connect_host, args.connect_port),
            forward_address if forward_address else ("127.0.0.1", 80),
            sevent.utils.ensure_bytes(args.key), conns, status)
    sevent.current().call_async(check_timeout, conns, status, args.timeout)
Beispiel #20
0
def main(argv):
    global warp_write

    parser = argparse.ArgumentParser(description="tcp port forward")
    parser.add_argument(
        '-L',
        dest='forwards',
        default=[],
        action="append",
        type=str,
        help=
        'forward host, accept format [[local_bind:]local_port:remote_host:remote_port]|[subnet], support muiti forward args (example: 0.0.0.0:80:127.0.0.1:8088 or 80:192.168.0.2:8088|192.168.0.0/24)'
    )
    parser.add_argument('-t',
                        dest='timeout',
                        default=7200,
                        type=int,
                        help='no read/write timeout (default: 7200)')
    parser.add_argument('-s', dest='speed', default=0, type=lambda v: int(float(v[:-1]) * BYTES_MAP[v.upper()[-1]]) \
        if v and v.upper()[-1] in BYTES_MAP else int(float(v)), help='per connection speed limit byte, example: 1024 or 1M (default: 0 is unlimit), available units : B K M G T')
    parser.add_argument('-S', dest='global_speed', default=0, type=lambda v: int(float(v[:-1]) * BYTES_MAP[v.upper()[-1]]) \
        if v and v.upper()[-1] in BYTES_MAP else int(float(v)), help='global speed limit byte, example: 1024 or 1M (default: 0 is unlimit), available units : B K M G T')
    parser.add_argument('-d', dest='delay', default=0, type=lambda v: (float(v.split("-")[0]), float(v.split("-")[-1])) \
        if v and isinstance(v, str) and "-" in v else float(v), help='delay millisecond (default: 0 is not delay, example -d100 or -d100-200), the - between two numbers will be random delay')
    parser.add_argument(
        '-M',
        dest='mirror_host',
        default="",
        type=str,
        help=
        'mirror host, accept format [[up_host:]up_port:[down_host]:down_port] (example: 0.0.0.0:80:127.0.0.1:8088 or :127.0.0.1:8088 or 127.0.0.1:8088: or 8088:8088)'
    )
    parser.add_argument(
        '-F',
        dest='mirror_header',
        default="",
        type=str,
        help=
        'mirror header, accept variables [from_host|from_port|to_host|to_port|conn_id] (example: "{conn_id}-{from_host}:{from_port}->{to_host}:{to_port}\\r\\n")'
    )
    args = parser.parse_args(args=argv)
    config_signal()
    if not args.forwards:
        exit(0)

    forwards = {}
    for forward in args.forwards:
        hosts, subnet = host_parse(forward)
        if hosts[0] not in forwards:
            forwards[hosts[0]] = []
        forwards[hosts[0]].append((hosts[1], subnet))
    if not forwards:
        exit(0)

    if args.speed or args.global_speed:
        warp_write = warp_speed_limit_write

    if args.delay:
        warp_write = warp_delay_write(
            Delayer(
                0 if isinstance(args.delay, tuple) else float(args.delay) /
                1000.0,
                (int(args.delay[0] * 1000),
                 int(args.delay[1] *
                     1000)) if isinstance(args.delay, tuple) else None),
            warp_write)

    if args.mirror_host:
        warp_write = warp_mirror_write(args.mirror_host, args.mirror_header,
                                       warp_write)

    forward_servers = []
    for bind_address, forward_hosts in forwards.items():
        server = create_server(bind_address)
        forward_servers.append(
            (server,
             sorted(forward_hosts,
                    key=lambda x: x[1][1][0] * 0xffffffffffffffff + x[1][1][1]
                    if isinstance(x[1][1], tuple) else x[1][1],
                    reverse=True)))
        logging.info("port forward listen %s:%s", bind_address[0],
                     bind_address[1])

    sevent.current().call_async(tcp_forward_servers, forward_servers,
                                args.timeout, int(args.speed / 10),
                                int(args.global_speed / 10))
Beispiel #21
0
    def _(data):
        if conn_id in speed_limiter.buffers:
            current_speed = status[current_speed_key]
            if current_speed <= 0:
                return

            if speed_limiter.global_speed:
                if speed_limiter.current_speed <= 0:
                    return

                dl = len(data)
                speed = min(speed_limiter.current_speed, current_speed)
                if dl > speed:
                    status[key] += buffer.fetch(data, speed)
                    speed_limiter.current_speed -= speed
                    status[current_speed_key] -= speed
                    return origin_write(buffer)

                status[key] += dl
                speed_limiter.current_speed -= dl
                status[current_speed_key] -= dl
                return origin_write(data)

            dl = len(data)
            if dl > current_speed:
                status[key] += buffer.fetch(data, current_speed)
                status[current_speed_key] = 0
                return origin_write(buffer)

            status[key] += dl
            status[current_speed_key] -= dl
            return origin_write(data)

        speed_limiter.buffers[conn_id] = (data, speed_write)
        if not speed_limiter.is_running:
            speed_limiter.is_running = True
            sevent.current().call_async(speed_limiter.loop)

        dl = len(data)
        if speed_limiter.global_speed:
            if speed_limiter.current_speed <= 0:
                status[current_speed_key] = 0
                return
            speed = min(speed_limiter.current_speed, speed_limiter.speed)
            if dl > speed:
                status[key] += buffer.fetch(data, speed)
                speed_limiter.current_speed -= speed
                status[current_speed_key] = 0
                return origin_write(buffer)

            status[key] += dl
            speed_limiter.current_speed -= dl
            status[current_speed_key] = speed_limiter.speed - dl
            return origin_write(data)

        if dl > speed_limiter.speed:
            status[key] += buffer.fetch(data, speed_limiter.speed)
            status[current_speed_key] = 0
            return origin_write(buffer)

        status[key] += dl
        status[current_speed_key] = speed_limiter.speed - dl
        return origin_write(data)