Package: pproxy
HTTP/HTTP2/HTTP3/Socks4/Socks5/Shadowsocks/SSH/Redirect/Pf/QUIC TCP/UDP asynchronous tunnel proxy implemented in Python3 asyncio.QuickStart$ pip3 install pproxySuccessfully installed pproxy-1.9.5$ pproxyServing on :8080 by http,socks4,socks5^C$ pproxy -l ss://chacha20:abc@:8080Serving on :8080 by ss (chacha20-py)Optional: (better performance with C ciphers)$ pip3 install pproxy[accelerated]Successfully installed pycryptodome-3.6.4Apply OS system-wide proxy: (MacOS, Windows)$ pproxy -r ss://chacha20:abc@server_ip:8080 --sys -vvServing on :8080 by http,socks4,socks5System proxy setting -> socks5 localhost:8080socks5 ::1:57345 -> ss server_ip:8080 -> slack.com:443socks5 ::1:57345 -> ss server_ip:8080 -> www.google.com:443..... (all local traffic log) ......Apply CLI proxy: (MacOS, Linux)$ export http_proxy=http://localhost:8080$ export https_proxy=http://localhost:8080Run With DockerpproxyDocker container has both python3 (with Cryptodome for performance optimizations) andpypyversions available.Python3:docker run-it-p8080:8080 mosajjal/pproxy:latest-lhttp://:8080-vvPypy3:docker run-it-p8080:8080mosajjal/pproxy:latest-pypy-lhttp://:8080-vvFeaturesLightweight single-thread asynchronous IO.Pure python, no additional library required.Proxy client/server for TCP/UDP.Schedule (load balance) among remote servers.Incoming traffic auto-detect.Tunnel/jump/backward-jump support.Unix domain socket support.HTTP v2, HTTP v3 (QUIC)User/password authentication support.Filter/block hostname by regex patterns.SSL/TLS client/server support.Shadowsocks OTA (One-Time-Auth), SSR plugins.Statistics by bandwidth and traffic.PAC support for javascript configuration.Iptables/Pf NAT redirect packet tunnel.System proxy auto-setting support.Client/Server API provided.ProtocolsNameTCP serverTCP clientUDP serverUDP clientschemehttp (connect)✔✔http://http
(get,post,etc)✔httponly://
(as client)http v2 (connect)✔✔h2://http v3 (connect)✔ by UDP✔ by UDPh3://https✔✔http+ssl://socks4✔✔socks4://socks5✔✔✔ udp-only✔ udp-onlysocks5://socks5 over TLS✔✔socks5+ssl://shadowsocks✔✔✔✔ss://shadowsocks aead✔✔ss://shadowsocksR✔✔ssr://trojan✔✔trojan://ssh tunnel✔ssh://quic✔ by UDP✔ by UDP✔✔http+quic://iptables nat✔redir://pfctl nat (macos)✔pf://echo✔✔echo://tunnel
(raw socket)✔✔✔✔tunnel://
tunnel{ip}://websocket
(simple tunnel)✔✔ws://
ws{dst_ip}://xxx over TLS✔✔xxx+ssl://AUTO DETECT✔✔a+b+c+d://Scheduling AlgorithmsNameTCPUDPParameterDefaultfirst_available✔✔-s fa✔round_robin✔✔-s rrrandom_choice✔✔-s rcleast_connection✔-s lcRequirementpycryptodomeis an optional library to enable faster (C version) cipher.pproxyhas many built-in pure python ciphers. They are lightweight and stable, but slower than C ciphers. After speedup withPyPy, pure python ciphers can get similar performance as C version. If the performance is important and don’t havePyPy, installpycryptodomeinstead.asyncsshis an optional library to enable ssh tunnel client support.These are some performance benchmarks between Python and C ciphers (dataset: 8M):chacha20-c0.64 secschacha20-py (pypy3)1.32 secschacha20-py48.86 secsPyPy3 Quickstart:$ pypy3 -m ensurepip$ pypy3 -m pip install asyncio pproxyUsage$ pproxy -husage: pproxy [-h] [-l LISTEN] [-r RSERVER] [-ul ULISTEN] [-ur URSERVER][-b BLOCK] [-a ALIVED] [-v] [--ssl SSLFILE] [--pac PAC][--get GETS] [--sys] [--test TESTURL] [--version]Proxy server that can tunnel among remote servers by regex rules. Supportedprotocols: http,socks4,socks5,shadowsocks,shadowsocksr,redirect,pf,tunneloptional arguments:-h, --help        show this help message and exit-l LISTEN         tcp server uri (default: http+socks4+socks5://:8080/)-r RSERVER        tcp remote server uri (default: direct)-ul ULISTEN       udp server setting uri (default: none)-ur URSERVER      udp remote server uri (default: direct)-b BLOCK          block regex rules-a ALIVED         interval to check remote alive (default: no check)-s {fa,rr,rc,lc}  scheduling algorithm (default: first_available)-v                print verbose output--ssl SSLFILE     certfile[,keyfile] if server listen in ssl mode--pac PAC         http PAC path--get GETS        http custom {path,file}--sys             change system proxy setting (mac, windows)--test TEST       test this url for all remote proxies and exit--version         show program's version number and exitOnline help: <https://github.com/qwj/python-proxy>URI Syntax{scheme}://[{cipher}@]{netloc}/[@{localbind}][,{plugins}][?{rules}][#{auth}]schemeCurrently supported scheme: http, socks, ss, ssl, secure. You can use + to link multiple protocols together.httphttp protocol (CONNECT)httponlyhttp protocol (GET/POST)socks4socks4 protocolsocks5socks5 protocolssshadowsocks protocolssrshadowsocksr (SSR) protocoltrojantrojanprotocolsshssh client tunnelredirredirect (iptables nat)pfpfctl (macos pf nat)sslunsecured ssl/tls (no cert)securesecured ssl/tls (cert)tunnelraw connectionwswebsocket connectionechoecho-back servicedirectdirect connection“http://” accepts GET/POST/CONNECT as server, sends CONNECT as client. “httponly://” sends “GET/POST” as client, works only on http traffic.Valid schemes:http://, http+socks4+socks5://, http+ssl://, ss+secure://, http+socks5+ss://Invalid schemes: ssl://, secure://cipherCipher’s format: “cipher_name:cipher_key”. Cipher can be base64-encoded. So cipher string with “YWVzLTEyOC1nY206dGVzdA==” is equal to “aes-128-gcm:test”.Full cipher support list:CipherKey LengthIV LengthScore (0-5)table-pyany00 (lowest)rc41600 (lowest)rc4-md516160.5chacha203285 (highest)chacha20-ietf32125chacha20-ietf-
poly1305-py3232AEADsalsa203284.5aes-128-cfbaes-128-cfb8aes-128-cfb1-py16163slowaes-192-cfbaes-192-cfb8aes-192-cfb1-py24163.5slowaes-256-cfbaes-256-ctraes-256-ofbaes-256-cfb8aes-256-cfb1-py32164.5slowaes-256-gcmaes-192-gcmaes-128-gcm322416322416AEADAEADAEADcamellia-256-cfbcamellia-192-cfbcamellia-128-cfb322416161616444bf-cfb1681cast5-cfb1682.5des-cfb881.5rc2-cfb-py1682idea-cfb-py1682.5seed-cfb-py16162pproxyciphers have pure python implementations. Program will switch to C cipher if there is C implementation available withinpycryptodome. Otherwise, use pure python cipher.AEAD ciphers use additional payload after each packet. The underlying protocol is different. Specifications:AEAD.Some pure python ciphers (aes-256-cfb1-py) is quite slow, and is not recommended to use without PyPy speedup. Try installpycryptodomeand use C version cipher instead.To enable OTA encryption with shadowsocks, add ‘!’ immediately after cipher name.netlocIt can be “hostname:port” or “/unix_domain_socket”. If the hostname is empty, server will listen on all interfaces.Valid netloc: localhost:8080, 0.0.0.0:8123, /tmp/domain_socket, :8123localbindIt can be “@in” or @ipv4_address or @ipv6_addressValid localbind: @in, @192.168.1.15, @::1pluginsIt can be multiple plugins joined by “,”. Supported plugins: plain, origin, http_simple, tls1.2_ticket_auth, verify_simple, verify_deflateValid plugins: /,tls1.2_ticket_auth,verify_simplerulesThe filename that contains regex rulesauthThe username, colon ‘:’, and the passwordURIs can be joined by “__” to indicate tunneling by jump. For example, ss://1.2.3.4:1324__http://4.5.6.7:4321 make remote connection to the first shadowsocks proxy server, and then jump to the second http proxy server.Client APITCP Client APIimport asyncio, pproxyasync def test_tcp(proxy_uri):conn = pproxy.Connection(proxy_uri)reader, writer = await conn.tcp_connect('google.com', 80)writer.write(b'GET / HTTP/1.1\r\n\r\n')data = await reader.read(1024*16)print(data.decode())asyncio.run(test_tcp('ss://aes-256-cfb:password@remote_host:remote_port'))UDP Client APIimport asyncio, pproxyasync def test_udp(proxy_uri):conn = pproxy.Connection(proxy_uri)answer = asyncio.Future()await conn.udp_sendto('8.8.8.8', 53, b'hello the world', answer.set_result)await answerprint(answer.result())asyncio.run(test_udp('ss://chacha20:password@remote_host:remote_port'))Server APIServer API example:import asyncioimport pproxyserver = pproxy.Server('ss://0.0.0.0:1234')remote = pproxy.Connection('ss://1.2.3.4:5678')args = dict( rserver = [remote],verbose = print )loop = asyncio.get_event_loop()handler = loop.run_until_complete(server.start_server(args))try:loop.run_forever()except KeyboardInterrupt:print('exit!')handler.close()loop.run_until_complete(handler.wait_closed())loop.run_until_complete(loop.shutdown_asyncgens())loop.close()ExamplesRegex ruleDefine regex file “rules” as follow:#google domains(?:.+\.)?google.*\.com(?:.+\.)?gstatic\.com(?:.+\.)?gmail\.com(?:.+\.)?ntp\.org(?:.+\.)?glpals\.com(?:.+\.)?akamai.*\.net(?:.+\.)?ggpht\.com(?:.+\.)?android\.com(?:.+\.)?gvt1\.com(?:.+\.)?youtube.*\.com(?:.+\.)?ytimg\.com(?:.+\.)?goo\.gl(?:.+\.)?youtu\.be(?:.+\.)?google\..+Then startpproxy$ pproxy -r http://aa.bb.cc.dd:8080?rules -vvServing on :8080 by http,socks4,socks5http ::1:57768 -> http aa.bb.cc.dd:8080 -> www.googleapis.com:443http ::1:57772 -> www.yahoo.com:80socks4 ::1:57770 -> http aa.bb.cc.dd:8080 -> www.youtube.com:443pproxywill serve incoming traffic by http/socks4/socks5 auto-detect protocol, redirect all google traffic to http proxy aa.bb.cc.dd:8080, and visit all other traffic directly from local.Use cipherAdd cipher encryption to make sure data can’t be intercepted. Runpproxylocally as:$ pproxy -l ss://:8888 -r ss://chacha20:cipher_key@aa.bb.cc.dd:12345 -vvNext, run pproxy.py remotely on server “aa.bb.cc.dd”. The base64 encoded string of “chacha20:cipher_key” is also supported:$ pproxy -l ss://chacha20:cipher_key@:12345The same as:$ pproxy -l ss://Y2hhY2hhMjA6Y2lwaGVyX2tleQ==@:12345The traffic between local and aa.bb.cc.dd is encrypted by stream cipher Chacha20 with secret key “cipher_key”.Unix domain socketA more complex example:$ pproxy -l ss://salsa20!:complex_cipher_key@/tmp/pproxy_socket -r http+ssl://domain1.com:443#username:passwordpproxylisten on the unix domain socket “/tmp/pproxy_socket” with cipher “salsa20” and key “complex_cipher_key”. OTA packet protocol is enabled by adding ! after cipher name. The traffic is tunneled to remote https proxy with simple http authentication.SSL/TLS serverIf you want to listen in SSL/TLS, you must specify ssl certificate and private key files by parameter “–ssl”:$ pproxy -l http+ssl://0.0.0.0:443 -l http://0.0.0.0:80 --ssl server.crt,server.key --pac /autopacpproxylisten on both 80 HTTP and 443 HTTPS ports, use the specified SSL/TLS certificate and private key files. The “–pac” enable PAC feature, so you can put “https://yourdomain.com/autopac” path in your device’s auto-configure url.Simple guide for generating self-signed ssl certificates:$ openssl genrsa -des3 -out server.key 1024$ openssl req -new -key server.key -out server.csr$ cp server.key server.key.org$ openssl rsa -in server.key.org -out server.key$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crtSSR pluginsShadowsocksR example with plugin “tls1.2_ticket_auth” to emulate common tls traffic:$ pproxy -l ssr://chacha20:mypass@0.0.0.0:443/,tls1.2_ticket_auth,verify_simpleLocal bind ipIf you want to route the traffic by different local bind, use the @localbind URI syntax. For example, server has three ip interfaces: 192.168.1.15, 111.0.0.1, 112.0.0.1. You want to route traffic matched by “rule1” to 111.0.0.2 and traffic matched by “rule2” to 222.0.0.2, and the remaining traffic directly:$ pproxy -l ss://:8000/@in -r ss://111.0.0.2:8000/@111.0.0.1?rule1 -r ss://222.0.0.2:8000/@222.0.0.1?rule2Redirect/Pf protocolIPTable NAT redirect example (Ubuntu):$ sudo iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-ports 5555$ pproxy -l redir://:5555 -r http://remote_http_server:3128 -vvThe above example illustrates how to redirect all local output tcp traffic with destination port 80 to localhost port 5555 listened bypproxy, and then tunnel the traffic to remote http proxy.PF redirect example (MacOS):$ sudo pfctl -ef /dev/stdinrdr pass on lo0 inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080pass out on en0 route-to lo0 inet proto tcp from any to any port 80 keep state^D$ sudo pproxy -l pf://:8080 -r socks5://remote_socks5_server:1324 -vvMake surepproxyruns in root mode (sudo), otherwise it cannot redirect pf packet.Multiple jumps example$ pproxy -r http://server1__ss://server2__socks://server3pproxywill connect to server1 first, tell server1 connect to server2, and tell server2 connect to server3, and make real traffic by server3.Raw connection tunnelTCP raw connection tunnel example:$ pproxy -l tunnel{google.com}://:80$ curl -H "Host: google.com" http://localhostUDP dns tunnel example:$ pproxy -ul tunnel{8.8.8.8}://:53$ nslookup google.com localhostUDP more complicated exampleRun the shadowsocks udp proxy on remote machine:$ pproxy -ul ss://remote_server:13245Run the commands on local machine:$ pproxy -ul tunnel{8.8.8.8}://:53 -ur ss://remote_server:13245 -vvUDP tunnel 127.0.0.1:60573 -> ss remote_server:13245 -> 8.8.8.8:53UDP tunnel 127.0.0.1:60574 -> ss remote_server:13245 -> 8.8.8.8:53...$ nslookup google.com localhostLoad balance exampleSpecify multiple -r server, and a scheduling algorithm (rr = round_robin, rc = random_choice, lc = least_connection):$ pproxy -r http://server1 -r ss://server2 -r socks5://server3 -s rr -vvhttp ::1:42356 -> http server1 -> google.com:443http ::1:42357 -> ss server2 -> google.com:443http ::1:42358 -> socks5 server3 -> google.com:443http ::1:42359 -> http server1 -> google.com:443...$ pproxy -ul tunnel://:53 -ur tunnel://8.8.8.8:53 -ur tunnel://8.8.4.4:53 -s rc -vvUDP tunnel ::1:35378 -> tunnel 8.8.8.8:53UDP tunnel ::1:35378 -> tunnel 8.8.4.4:53...WebSocket exampleWebSocket protocol is similar to Tunnel protocol. It is raw and doesn’t support any proxy function. It can connect to other proxy like Tunnel protocol.First run pproxy on remote machine:$ pproxy -l ws://:80 -r tunnel:///tmp/myproxy -v$ pproxy -l ss://chacha20:abc@/tmp/myproxy -vRun pproxy on local machine:$ pproxy -l tunnel://:1234 -r ws://remote_ip:80 -vvThen port :1234 on local machine is connected to the /tmp/myproxy on remote machine by WebSocket tunnel. You can specify any proxy protocol details on /tmp/myproxy.It is a good practice to use some CDN in the middle of local/remote machines. CDN with WebSocket support can hide remote machine’s real IP from public.Backward proxySometimes, the proxy server hides behind an NAT router and doesn’t have a public ip. The client side has a public ip “client_ip”. Backward proxy feature enables the server to connect backward to client and wait for proxy requests.Runpproxyclient as follows:$ pproxy -l http://:8080 -r http+in://:8081 -vRunpproxyserver as follows:$ pproxy -l http+in://client_ip:8081Server connects to client_ip:8081 and waits for client proxy requests. The protocol http specified is just an example. It can be any protocol and cipherpproxysupports. The scheme “in” should exist in URI to informpproxythat it is a backward proxy.$ pproxy -l http+in://jumpserver__http://client_ip:8081It is a complicated example. Server connects to client_ip:8081 by jumphttp://jumpserver. The backward proxy works through jumps.SSH client tunnelSSH client tunnel support is enabled by installing additional libraryasyncssh. After “pip3 install asyncssh”, you can specify “ssh” as scheme to proxy via ssh client tunnel.$ pproxy -l http://:8080 -r ssh://remote_server.com/#login:passwordIf a client private key is used to authenticate, put double colon “::” between login and private key path.$ pproxy -l http://:8080 -r ssh://remote_server.com/#login::private_key_pathSSH connection known_hosts feature is disabled by default.SSH jumpSSH jump is supported by using “__” concatenation$ pproxy -r ssh://server1__ssh://server2__ssh://server3First connection to server1 is made. Second, ssh connection to server2 is made from server1. Finally, connect to server3, and use server3 for proxying traffic.SSH remote forward$ pproxy -l ssh://server__tunnel://0.0.0.0:1234 -r tunnel://127.0.0.1:1234TCP :1234 on remote server is forwarded to 127.0.0.1:1234 on local server$ pproxy -l ssh://server1__ssh://server2__ss://0.0.0.0:1234 -r ss://server3:1234It is a complicated example. SSH server2 is jumped from SSH server1, and ss://0.0.0.0:1234 on server2 is listened. Traffic is forwarded to ss://server3:1234.Trojan protocol exampleNormally trojan:// should be used together with ssl://. You should specify the SSL crt/key file for ssl usage. A typical trojan server would be:$ pproxy --ssl ssl.crt,ssl.key -l trojan+tunnel{localhost:80}+ssl://:443#yourpassword -vvIf trojan password doesn’t match, the tunnal{localhost:80} will be switched to. It looks exactly the same as a common HTTPS website.QUIC protocol exampleQUIC is a UDP stream protocol used in HTTP/3. Libraryaioquicis required if you want to proxy via QUIC.
QUIC is listened on UDP port, but can handle TCP or UDP traffic. If you want to handle TCP traffic, you should use “-l quic+http” instead of “-ul quic+http”.$ pip3 install aioquic$ pproxy --ssl ssl.crt,ssl.key -l quic+http://:1234On the client:$ pproxy -r quic+http://server:1234QUIC protocol can transfer a lot of TCP streams on one single UDP stream. If the connection number is hugh, QUIC can benefit by reducing TCP handshake time.VPN Server ExampleYou can run VPN server simply by installing pvpn (python vpn), a lightweight VPN server with pproxy tunnel feature.$ pip3 install pvpnSuccessfully installed pvpn-0.2.1$ pvpn -wg 9999 -r http://remote_server:remote_portServing on UDP :500 :4500...Serving on UDP :9000 (WIREGUARD)...TCP xx.xx.xx.xx:xx -> HTTP xx.xx.xx.xx:xx -> xx.xx.xx.xx:xxProjectspython-vpn- VPN Server (IPSec,IKE,IKEv2,L2TP,WireGuard) in pure pythonshadowproxy- Awesome python proxy implementation by guyingbo