Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rules seem to be ignored with 'direct' #177

Open
MartinusR opened this issue Jan 25, 2024 · 3 comments
Open

Rules seem to be ignored with 'direct' #177

MartinusR opened this issue Jan 25, 2024 · 3 comments

Comments

@MartinusR
Copy link

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
@MartinusR MartinusR changed the title Rules do not work with "direct" Rules seem to be ignore with 'direct' Jan 25, 2024
@MartinusR MartinusR changed the title Rules seem to be ignore with 'direct' Rules seem to be ignored with 'direct' Jan 25, 2024
@gordon-quad
Copy link

gordon-quad commented Mar 9, 2024

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.

@gordon-quad
Copy link

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)

@Jonney
Copy link
Contributor

Jonney commented Apr 25, 2024

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())

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants