From 697635c0b7c786faaa6053f8bf2ac514d5bc7260 Mon Sep 17 00:00:00 2001 From: Milan Hauth Date: Sun, 12 Dec 2021 11:56:04 +0100 Subject: [PATCH 1/3] print effective port when port is automatic (zero) --- pproxy/server.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/pproxy/server.py b/pproxy/server.py index d13aa37..1209767 100644 --- a/pproxy/server.py +++ b/pproxy/server.py @@ -874,6 +874,17 @@ async def test_url(url, rserver): print(body.decode('utf8', 'ignore')) print(f'============ success ============') +def print_server_started(option, server, print_fn): + for s in server.sockets: + # https://github.com/MagicStack/uvloop/blob/master/uvloop/pseudosock.pyx + laddr = s.getsockname() # tuple size varies with protocol family + h = laddr[0] + p = laddr[1] + f = str(s.family) + ipversion = "ipv4" if f == "AddressFamily.AF_INET" else ("ipv6" if f == "AddressFamily.AF_INET6" else "ipv?") # TODO better + bind = ipversion+' '+h+':'+str(p) + print_fn(option, bind) + def main(args = None): parser = argparse.ArgumentParser(description=__description__+'\nSupported protocols: http,socks4,socks5,shadowsocks,shadowsocksr,redirect,pf,tunnel', epilog=f'Online help: <{__url__}>') parser.add_argument('-l', dest='listen', default=[], action='append', type=proxies_by_uri, help='tcp server uri (default: http+socks4+socks5://:8080/)') @@ -936,27 +947,36 @@ def main(args = None): from . import verbose verbose.setup(loop, args) servers = [] + def print_fn(option, bind=None): + print('Serving on', (bind or option.bind), 'by', ",".join(i.name for i in option.protos) + ('(SSL)' if option.sslclient else ''), '({}{})'.format(option.cipher.name, ' '+','.join(i.name() for i in option.cipher.plugins) if option.cipher and option.cipher.plugins else '') if option.cipher else '') for option in args.listen: - print('Serving on', option.bind, 'by', ",".join(i.name for i in option.protos) + ('(SSL)' if option.sslclient else ''), '({}{})'.format(option.cipher.name, ' '+','.join(i.name() for i in option.cipher.plugins) if option.cipher and option.cipher.plugins else '') if option.cipher else '') try: server = loop.run_until_complete(option.start_server(vars(args))) + print_server_started(option, server, print_fn) servers.append(server) except Exception as ex: + print_fn(option) print('Start server failed.\n\t==>', ex) + def print_fn(option, bind=None): + print('Serving on UDP', (bind or option.bind), 'by', ",".join(i.name for i in option.protos), f'({option.cipher.name})' if option.cipher else '') for option in args.ulisten: - print('Serving on UDP', option.bind, 'by', ",".join(i.name for i in option.protos), f'({option.cipher.name})' if option.cipher else '') try: server, protocol = loop.run_until_complete(option.udp_start_server(vars(args))) + print_server_started(option, server, print_fn) servers.append(server) except Exception as ex: + print_fn(option) print('Start server failed.\n\t==>', ex) + def print_fn(option, bind=None): + print('Serving on', (bind or option.bind), 'backward by', ",".join(i.name for i in option.protos) + ('(SSL)' if option.sslclient else ''), '({}{})'.format(option.cipher.name, ' '+','.join(i.name() for i in option.cipher.plugins) if option.cipher and option.cipher.plugins else '') if option.cipher else '') for option in args.rserver: if isinstance(option, ProxyBackward): - print('Serving on', option.bind, 'backward by', ",".join(i.name for i in option.protos) + ('(SSL)' if option.sslclient else ''), '({}{})'.format(option.cipher.name, ' '+','.join(i.name() for i in option.cipher.plugins) if option.cipher and option.cipher.plugins else '') if option.cipher else '') try: server = loop.run_until_complete(option.start_backward_client(vars(args))) + print_server_started(option, server, print_fn) servers.append(server) except Exception as ex: + print_fn(option) print('Start server failed.\n\t==>', ex) if servers: if args.sys: From fe495ce21a2acadf7b3949288bb887fe8f3468c3 Mon Sep 17 00:00:00 2001 From: mervent Date: Wed, 16 Mar 2022 21:04:28 +0300 Subject: [PATCH 2/3] Obey RFC2616 https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html An HTTP/1.1 proxy MUST ensure that any request message it forwards does contain an appropriate Host header field that identifies the service being requested by the proxy. All Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad Request) status code to any HTTP/1.1 request message which lacks a Host header field. --- pproxy/proto.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pproxy/proto.py b/pproxy/proto.py index eb40287..1572fb4 100644 --- a/pproxy/proto.py +++ b/pproxy/proto.py @@ -328,8 +328,8 @@ async def connected(writer): writer.write(f'{method} {newpath} {ver}\r\n{lines}\r\n\r\n'.encode()) return True return user, host_name, port, connected - async def connect(self, reader_remote, writer_remote, rauth, host_name, port, myhost, **kw): - writer_remote.write(f'CONNECT {host_name}:{port} HTTP/1.1\r\nHost: {myhost}'.encode() + (b'\r\nProxy-Authorization: Basic '+base64.b64encode(rauth) if rauth else b'') + b'\r\n\r\n') + async def connect(self, reader_remote, writer_remote, rauth, host_name, port, **kw): + writer_remote.write(f'CONNECT {host_name}:{port} HTTP/1.1\r\nHost: {host_name}:{port}'.encode() + (b'\r\nProxy-Authorization: Basic '+base64.b64encode(rauth) if rauth else b'') + b'\r\n\r\n') await reader_remote.read_until(b'\r\n\r\n') async def http_channel(self, reader, writer, stat_bytes, stat_conn): try: From c970092aba12ece06ca466a11c8c45492fc357a4 Mon Sep 17 00:00:00 2001 From: Jonney Date: Mon, 27 Mar 2023 19:58:03 +0800 Subject: [PATCH 3/3] Compatible with Python 3.11 In Python 3.11, asyncio.sslproto.SSLProtocol inherits from asyncio.protocols.BufferedProtocol. In SSLProtocol, data_received() is no longer used and has been replaced with get_buffer() and buffer_updated(). --- pproxy/proto.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/pproxy/proto.py b/pproxy/proto.py index eb40287..a1bd1bb 100644 --- a/pproxy/proto.py +++ b/pproxy/proto.py @@ -616,12 +616,21 @@ def abort(self): self.close() ssl.connection_made(Transport()) async def channel(): + read_size=65536 + buffer=None + if hasattr(ssl,'get_buffer'): + buffer=ssl.get_buffer(read_size) try: while not reader.at_eof() and not ssl._app_transport._closed: - data = await reader.read(65536) + data = await reader.read(read_size) if not data: break - ssl.data_received(data) + if buffer!=None: + data_len=len(data) + buffer[:data_len]=data + ssl.buffer_updated(data_len) + else: + ssl.data_received(data) except Exception: pass finally: