Rules seem to be ignored with 'direct'
MartinusR opened this issue · 3 comments
I want to exclude local addresses from going through the proxy.
When I try to use direct with some rules, it seems that the rules are ignored and everything goes through direct:
pproxy -r direct://?rules -r socks5://server
With rules
containing:
localhost
Then for instance wget google.com
goes through direct:
http ::1:50386 -> google.com:80
If I create another local socks5 (or http) proxy that has no remote (direct only), this works:
pproxy -r socks5://direct_proxy?rules -r socks5://server
When i do wget google.com
, this is now working:
http ::1:50538 -> socks5 server -> google.com:80
It works with older (2.2.0) version, but not with recent one.
Unfortunately in 2.2.0 HTTP2 is broken (or not implemented). It would be really nice if this could be fixed.
Simple but ugly workaround
diff --git a/pproxy/server.py b/pproxy/server.py
index dc3e4e5..26963ce 100644
--- a/pproxy/server.py
+++ b/pproxy/server.py
@@ -153,11 +153,12 @@ async def check_server_alive(interval, rserver, verbose):
pass
class ProxyDirect(object):
- def __init__(self, lbind=None):
+ def __init__(self, rule=None, lbind=None):
self.bind = 'DIRECT'
self.lbind = lbind
self.unix = False
self.alive = True
+ self.rule = compile_rule(rule) if rule else None
self.connections = 0
self.udpmap = {}
@property
@@ -166,7 +167,7 @@ class ProxyDirect(object):
def logtext(self, host, port):
return '' if host == 'tunnel' else f' -> {host}:{port}'
def match_rule(self, host, port):
- return True
+ return (self.rule is None) or self.rule(host) or self.rule(str(port))
def connection_change(self, delta):
self.connections += delta
def udp_packet_unpack(self, data):
@@ -827,7 +828,7 @@ def proxy_by_uri(uri, jump):
auth = url.fragment.encode()
users = [i.rstrip() for i in auth.split(b'\n')] if auth else None
if 'direct' in protonames:
- return ProxyDirect(lbind=lbind)
+ return ProxyDirect(lbind=lbind, rule=url.query)
else:
params = dict(jump=jump, protos=protos, cipher=cipher, users=users, rule=url.query, bind=loc or urlpath,
host_name=host_name, port=port, unix=not loc, lbind=lbind, sslclient=sslclient, sslserver=sslserver)
This is my solution, no need to modify any code.
Just write your own code.
import asyncio
import uvloop
import signal
from pproxy import Server,Connection
from pproxy.server import ProxyDirect
HOSTS=(
'google.com',
'x.com',
'facebook.com',
)
LOCAL='http+socks5://127.0.0.1:8080'
REMOTE='ss://cipher:key@x.x.x.x:port'
def rule(host,port):
for item in HOSTS:
if host.endswith(item):
return True
async def main():
direct=ProxyDirect()
direct.match_rule=rule
server=Server(LOCAL)
handler=await server.start_server({
'rserver':(direct,Connection(REMOTE)),
'verbose':print,
'ruport':True,
})
stop=asyncio.Event()
signal.signal(signal.SIGINT,lambda sig,frame:stop.set())
await stop.wait()
handler.close()
if hasattr(handler,'wait_closed'):
await handler.wait_closed()
await asyncio.get_event_loop().shutdown_asyncgens()
if __name__=='__main__':
uvloop.install()
asyncio.run(main())