Code Monkey home page Code Monkey logo

python-proxy's Introduction

python-proxy

made-with-python PyPI-version Hit-Count Downloads Downloads-month Downloads-week

HTTP/HTTP2/HTTP3/Socks4/Socks5/Shadowsocks/SSH/Redirect/Pf/QUIC TCP/UDP asynchronous tunnel proxy implemented in Python3 asyncio.

QuickStart

$ pip3 install pproxy
Successfully installed pproxy-1.9.5
$ pproxy
Serving on :8080 by http,socks4,socks5
^C
$ pproxy -l ss://chacha20:abc@:8080
Serving on :8080 by ss (chacha20-py)

Optional: (better performance with C ciphers)

$ pip3 install pproxy[accelerated]
Successfully installed pycryptodome-3.6.4

Apply OS system-wide proxy: (MacOS, Windows)

$ pproxy -r ss://chacha20:abc@server_ip:8080 --sys -vv
Serving on :8080 by http,socks4,socks5
System proxy setting -> socks5 localhost:8080
socks5 ::1:57345 -> ss server_ip:8080 -> slack.com:443
socks5 ::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:8080

Run With Docker

pproxy Docker container has both python3 (with Cryptodome for performance optimizations) and pypy versions available.

Python3:

docker run -it -p 8080:8080 mosajjal/pproxy:latest -l http://:8080 -vv

Pypy3:

docker run -it -p 8080:8080 mosajjal/pproxy:latest-pypy -l http://:8080 -vv

Features

  • Lightweight 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.

Protocols

+-------------------+------------+------------+------------+------------+--------------+ | Name | TCP server | TCP client | UDP server | UDP client | scheme | +===================+============+============+============+============+==============+ | http (connect) | ✔ | ✔ | | | http:// | +-------------------+ +------------+------------+------------+--------------+ | http | | ✔ | | | httponly:// | | (get,post,etc) | | | | | (as client) | +-------------------+------------+------------+------------+------------+--------------+ | http v2 (connect) | ✔ | ✔ | | | h2:// | +-------------------+------------+------------+------------+------------+--------------+ | http v3 (connect) | ✔ by UDP | ✔ by UDP | | | h3:// | +-------------------+------------+------------+------------+------------+--------------+ | https | ✔ | ✔ | | | http+ssl:// | +-------------------+------------+------------+------------+------------+--------------+ | socks4 | ✔ | ✔ | | | socks4:// | +-------------------+------------+------------+------------+------------+--------------+ | socks5 | ✔ | ✔ | ✔ udp-only | ✔ udp-only | socks5:// | +-------------------+------------+------------+------------+------------+--------------+ | 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 | ✔ | ✔ | ✔ | ✔ | tunnel:// | | (raw socket) | | | | | tunnel{ip}://| +-------------------+------------+------------+------------+------------+--------------+ | websocket | ✔ | ✔ | | | ws:// | | (simple tunnel) | | | | | ws{dst_ip}://| +-------------------+------------+------------+------------+------------+--------------+ | xxx over TLS | ✔ | ✔ | | | xxx+ssl:// | +-------------------+------------+------------+------------+------------+--------------+ | AUTO DETECT | ✔ | | ✔ | | a+b+c+d:// | +-------------------+------------+------------+------------+------------+--------------+

Scheduling Algorithms

Name TCP UDP Parameter Default
first_available -s fa
round_robin -s rr
random_choice -s rc
least_connection -s lc

Requirement

pycryptodome is an optional library to enable faster (C version) cipher. pproxy has many built-in pure python ciphers. They are lightweight and stable, but slower than C ciphers. After speedup with PyPy, pure python ciphers can get similar performance as C version. If the performance is important and don't have PyPy, install pycryptodome instead.

asyncssh is an optional library to enable ssh tunnel client support.

These are some performance benchmarks between Python and C ciphers (dataset: 8M):

chacha20-c 0.64 secs
chacha20-py (pypy3) 1.32 secs
chacha20-py 48.86 secs

PyPy3 Quickstart:

$ pypy3 -m ensurepip
$ pypy3 -m pip install asyncio pproxy

Usage

$ pproxy -h
usage: 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. Supported
protocols: http,socks4,socks5,shadowsocks,shadowsocksr,redirect,pf,tunnel

optional 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 exit

Online help: <https://github.com/qwj/python-proxy>

URI Syntax

{scheme}://[{cipher}@]{netloc}/[@{localbind}][,{plugins}][?{rules}][#{auth}]
  • scheme
    • Currently supported scheme: http, socks, ss, ssl, secure. You can use + to link multiple protocols together.

      http http protocol (CONNECT)
      httponly http protocol (GET/POST)
      socks4 socks4 protocol
      socks5 socks5 protocol
      ss shadowsocks protocol
      ssr shadowsocksr (SSR) protocol
      trojan trojan protocol
      ssh ssh client tunnel
      redir redirect (iptables nat)
      pf pfctl (macos pf nat)
      ssl unsecured ssl/tls (no cert)
      secure secured ssl/tls (cert)
      tunnel raw connection
      ws websocket connection
      echo echo-back service
      direct direct 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://
  • cipher
    • Cipher'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:

      Cipher Key Length IV Length Score (0-5)
      table-py any 0 0 (lowest)
      rc4 16 0 0 (lowest)
      rc4-md5 16 16 0.5
      chacha20 32 8 5 (highest)
      chacha20-ietf 32 12 5
      chacha20-ietf-poly1305-py 32 32 AEAD
      salsa20 32 8 4.5

      aes-128-cfb

      aes-128-cfb8

      aes-128-cfb1-py

      16 16

      3

      slow

      aes-192-cfb

      aes-192-cfb8

      aes-192-cfb1-py

      24 16

      3.5

      slow

      aes-256-cfb

      aes-256-ctr

      aes-256-ofb

      aes-256-cfb8

      aes-256-cfb1-py

      32 16

      4.5

      slow

      aes-256-gcm

      aes-192-gcm

      aes-128-gcm

      32

      24

      16

      32

      24

      16

      AEAD

      AEAD

      AEAD

      camellia-256-cfb

      camellia-192-cfb

      camellia-128-cfb

      32

      24

      16

      16

      16

      16

      4

      4

      4

      bf-cfb 16 8 1
      cast5-cfb 16 8 2.5
      des-cfb 8 8 1.5
      rc2-cfb-py 16 8 2
      idea-cfb-py 16 8 2.5
      seed-cfb-py 16 16 2
    • pproxy ciphers have pure python implementations. Program will switch to C cipher if there is C implementation available within pycryptodome. 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 install pycryptodome and use C version cipher instead.
    • To enable OTA encryption with shadowsocks, add '!' immediately after cipher name.
  • netloc
    • It 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, :8123
  • localbind
    • It can be "@in" or @ipv4_address or @ipv6_address
    • Valid localbind: @in, @192.168.1.15, @::1
  • plugins
    • It can be multiple plugins joined by ",". Supported plugins: plain, origin, http_simple, tls1.2_ticket_auth, verify_simple, verify_deflate
    • Valid plugins: /,tls1.2_ticket_auth,verify_simple
  • rules
    • The filename that contains regex rules
  • auth
    • The username, colon ':', and the password

URIs 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 API

  • TCP Client API

    import asyncio, pproxy
    
    async 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 API

    import asyncio, pproxy
    
    async 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 answer
        print(answer.result())
    
    asyncio.run(test_udp('ss://chacha20:password@remote_host:remote_port'))

Server API

  • Server API example:

    import asyncio
    import pproxy
    
    server = 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()

Examples

  • Regex rule

    Define 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 start pproxy

    $ pproxy -r http://aa.bb.cc.dd:8080?rules -vv
    Serving on :8080 by http,socks4,socks5
    http ::1:57768 -> http aa.bb.cc.dd:8080 -> www.googleapis.com:443
    http ::1:57772 -> www.yahoo.com:80
    socks4 ::1:57770 -> http aa.bb.cc.dd:8080 -> www.youtube.com:443

    pproxy will 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 cipher

    Add cipher encryption to make sure data can't be intercepted. Run pproxy locally as:

    $ pproxy -l ss://:8888 -r ss://chacha20:[email protected]:12345 -vv

    Next, 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@:12345

    The same as:

    $ pproxy -l ss://Y2hhY2hhMjA6Y2lwaGVyX2tleQ==@:12345

    The traffic between local and aa.bb.cc.dd is encrypted by stream cipher Chacha20 with secret key "cipher_key".

  • Unix domain socket

    A more complex example:

    $ pproxy -l ss://salsa20!:complex_cipher_key@/tmp/pproxy_socket -r http+ssl://domain1.com:443#username:password

    pproxy listen 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 server

    If 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 /autopac

    pproxy listen 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.crt
  • SSR plugins

    ShadowsocksR example with plugin "tls1.2_ticket_auth" to emulate common tls traffic:

    $ pproxy -l ssr://chacha20:[email protected]:443/,tls1.2_ticket_auth,verify_simple
  • Local bind ip

    If 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?rule2
  • Redirect/Pf protocol

    IPTable 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 -vv

    The above example illustrates how to redirect all local output tcp traffic with destination port 80 to localhost port 5555 listened by pproxy, and then tunnel the traffic to remote http proxy.

    PF redirect example (MacOS):

    $ sudo pfctl -ef /dev/stdin
    rdr pass on lo0 inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
    pass 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 -vv

    Make sure pproxy runs in root mode (sudo), otherwise it cannot redirect pf packet.

  • Multiple jumps example

    $ pproxy -r http://server1__ss://server2__socks://server3

    pproxy will connect to server1 first, tell server1 connect to server2, and tell server2 connect to server3, and make real traffic by server3.

  • Raw connection tunnel

    TCP raw connection tunnel example:

    $ pproxy -l tunnel{google.com}://:80
    $ curl -H "Host: google.com" http://localhost

    UDP dns tunnel example:

    $ pproxy -ul tunnel{8.8.8.8}://:53
    $ nslookup google.com localhost
  • UDP more complicated example

    Run the shadowsocks udp proxy on remote machine:

    $ pproxy -ul ss://remote_server:13245

    Run the commands on local machine:

    $ pproxy -ul tunnel{8.8.8.8}://:53 -ur ss://remote_server:13245 -vv
    UDP tunnel 127.0.0.1:60573 -> ss remote_server:13245 -> 8.8.8.8:53
    UDP tunnel 127.0.0.1:60574 -> ss remote_server:13245 -> 8.8.8.8:53
    ...
    $ nslookup google.com localhost
  • Load balance example

    Specify 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 -vv
    http ::1:42356 -> http server1 -> google.com:443
    http ::1:42357 -> ss server2 -> google.com:443
    http ::1:42358 -> socks5 server3 -> google.com:443
    http ::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 -vv
    UDP tunnel ::1:35378 -> tunnel 8.8.8.8:53
    UDP tunnel ::1:35378 -> tunnel 8.8.4.4:53
    ...
  • WebSocket example

    WebSocket 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 -v

    Run pproxy on local machine:

    $ pproxy -l tunnel://:1234 -r ws://remote_ip:80 -vv

    Then 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 proxy

    Sometimes, 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.

    Run pproxy client as follows:

    $ pproxy -l http://:8080 -r http+in://:8081 -v

    Run pproxy server as follows:

    $ pproxy -l http+in://client_ip:8081

    Server 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 cipher pproxy supports. The scheme "in" should exist in URI to inform pproxy that it is a backward proxy.

    $ pproxy -l http+in://jumpserver__http://client_ip:8081

    It is a complicated example. Server connects to client_ip:8081 by jump http://jumpserver. The backward proxy works through jumps.

  • SSH client tunnel

    SSH client tunnel support is enabled by installing additional library asyncssh. 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:password

    If 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_path

    SSH connection known_hosts feature is disabled by default.

  • SSH jump

    SSH jump is supported by using "__" concatenation

    $ pproxy -r ssh://server1__ssh://server2__ssh://server3

    First 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:1234

    TCP :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:1234

    It 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 example

    Normally 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 -vv

    If 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 example

    QUIC is a UDP stream protocol used in HTTP/3. Library aioquic is 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://:1234

    On the client:

    $ pproxy -r quic+http://server:1234

    QUIC 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 Example

    You can run VPN server simply by installing pvpn (python vpn), a lightweight VPN server with pproxy tunnel feature.

    $ pip3 install pvpn
    Successfully installed pvpn-0.2.1
    $ pvpn -wg 9999 -r http://remote_server:remote_port
    Serving 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:xx

Projects

  • python-vpn - VPN Server (IPSec,IKE,IKEv2,L2TP,WireGuard) in pure python
  • shadowproxy - Awesome python proxy implementation by guyingbo

python-proxy's People

Contributors

keenser avatar mervent avatar milahu avatar moreati avatar mosajjal avatar qwj avatar valdikss avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-proxy's Issues

Several asyncio.ensure_future are never awaited

One should not "fire and forget" futures to work as "background tasks". This is very much like launching a thread and forgetting about it, when you probably should join it back at some point. This makes the code harder to reason about. One must properly await them, at some point in the future, and they're not even saved anywhere. See https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ for a good reasoning and their designed "nurseries" as to why this is good.

use case

I have the following use case:
1.1.1.1:1000 - a tcp service
2.2.2.2:2000 - a http proxy with authentication
On 3.3.3.3, i need to open a service which listens to port 3000, and tunnels all the requests to 1.1.1.1:1000 via the 2.2.2.2:2000 proxy.

So when i telnet 3.3.3.3:3000, i should be able to talk to 1.1.1.1:1000.

socat works just fine, but it creates a new pid for every connection and it is kind of slow and unreliable.
Can python-proxy be used for this case?

同主机多IP情况下,自身当独立代理服务器希望能采取适配性的IP策略

init.py代码53行可以改为:

server_ip = writer.get_extra_info('sockname')
if server_ip != '127.0.0.1':
    wait_connect = asyncio.open_connection(host=host_name, port=port, local_addr=(server_ip, 0))
else:
    wait_connect = asyncio.open_connection(host=host_name, port=port)

不太方便使用pr,希望可以改成类似这种,可以达到访问192.168.1.100使用100代理外网,访问192.168.1.101使用101代理外网,在单主机多IP的情况下特别方便,也可以加个argparse参数控制:-)

As Gateway

I thought that if I didn't specify remote, it would forward all traffic. After starting server and connecting via browser, all pages are blank. What did I miss?

import asyncio
import pproxy

server = pproxy.Server('http+socks5://0.0.0.0')

args = dict(verbose=print)

loop = asyncio.get_event_loop()
handler = loop.run_until_complete(server.start_server(args))
try:
    loop.run_forever()
except KeyboardInterrupt:
    print('exiting on interrupt')

handler.close()
loop.run_until_complete(handler.wait_closed())
loop.run_until_complete(loop.shutdown_asyncgens())
loop.close()

Usage with aiohttp ?

Hello
My use case is - to configure Connection with several relay socks proxies and to use it with aiohttp - how it is possible?
thanks

尝试使用客户端连接ss失败

安装python3.6
pip安装pproxy
客户端命令
➜ Python-3.6.0b2 pproxy -i http+socks://:1080 -r ss://aes-256-cfb:[email protected]:8088 -v
Serving on :1080 by socks,http
http wtfismyip.com:80 -> ss abc.net:8088
DIRECT: 0 (0.0K/s,0.0K/s) PROXY: 0 (0.0K/s,0.0K/s)

➜ ~ curl -x 127.0.0.1:1080 wtfismyip.com/json
会停在那里不反回

验证用sslocal是可以的。

Do not patch builtin classes

asyncio.StreamReader.read_ = lambda self: self.read(PACKET_SIZE)
asyncio.StreamReader.read_n = lambda self, n: asyncio.wait_for(self.readexactly(n), timeout=SOCKET_TIMEOUT)
asyncio.StreamReader.read_until = lambda self, s: asyncio.wait_for(self.readuntil(s), timeout=SOCKET_TIMEOUT)

It is very prone to breaking and should not be done. Consider sub-classing or making a proxy object instead. If anyone else were to do the same, this would break.

QUIC tunnel

Something like this has already been done in Go:

https://github.com/liudanking/quic-proxy

but I think it'll need a couple extra libraries. It's exteremely fast and reliable and it's somewhat undetected under a lot of Firewalls :)

UDP Connections do not seem to work

I have a simple SOCKS5 client which sends a UDP ASSOCIATE request.

I have expected python-proxy to let me establish UDP connections.
However, I get "Unknown SOCKS protocol" back. The code seems to assume that the client sends a regular TCP connection request:

assert (await reader.read_n(3)) == b'\x05\x01\x00', 'Unknown SOCKS protocol'

Are UDP connections out of scope?

Roadmap

Roadmap for pproxy. please keep this open

  • Configuration file support (yml file would be ideal)
  • Daemon mode support
  • Proper logging support (with levels/files/syslog support)
  • Ability to use base64: syntax for any input file (certificate etc) instead of providing the actual file
  • Implement more protocols (I have nothing in mind)
  • Handle SIGKILL etc. better
  • Multiple user authentication
  • Traffic statistics by domain, user, etc
  • Logging by domain, url, etc with different levels
  • Set outgoing traffic interface/IP
  • Better handling of first available and proxy checking (with timeouts and test URLs)

this will be updated and checkmarked as they're done.

wrong pip version

i've tried to install your package with pip3 and pip, both installs version 1.2.2

Socks5 relay uses a wrong protocol?

Hi, I am using pproxy as a socks5 relay server.
according to proto.py, Socks5.connect sends b'\x05\x01\x02\x01' + ... to server at first. But other socks5 clients only sends b'\x05\x02\x00\x01

Another proof is running two pproxy process, one is:

pproxy -l socks5://:8080/ -v

the other is:

pproxy -l socks5://:8081/ -v -r socks5://localhost:8080 --test http://ifconfig.co/

It results in Unsupported protocol b'1' from ::1 and Exception: Unknown remote protocol.

I am going to figure out the correct protocol then.

Thanks!

Authentication is sloppy

Hi, As you know, I've been using pproxy for a while now and I just found out there's a problem with the Authentication scheme. If I Authenticate once with the proxy, my public IP address remains authenticated with the server forever. After the first request, the auth becomes optional for that IP. Is that behavior intended? Because it would pose a big security vulnerability in public networks IMO

Consider to Refactor some parts of the code

The software is very good, working as expected.
But the code itself is REALLY HARD to read and follow.

Too much overuse lambda.
Difficult to expand the functionality for ordinary people like me.

Remote http+ssl not working

How to use properly remotes https://aa.bb.cc.dd proxies?

I have the following result:

[SSL: UNKNOWN_PROTOCOL] unknown protocol (_ssl.c:777) from 127.0.0.1

or

Unsupported protocol from 127.0.0.1

And my python request with this proxy listening

requests.exceptions.SSLError: HTTPSConnectionPool(host='domain.com', port=443): Max retries exceeded with url: /index (Caused by SSLError(SSLError("bad handshake: SysCallError(-1, 'Unexpected EOF')",),))

ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1051)

I had the problem with http+ssl with remote server:

SSL handshake failed
protocol: <asyncio.sslproto.SSLProtocol object at 0x7f2611d7eeb8>
transport: <_SelectorSocketTransport fd=10 read=polling write=<idle, bufsize=0>>
Traceback (most recent call last):
  File "/home/proxy-server/miniconda3/lib/python3.7/asyncio/sslproto.py", line 625, in _on_handshake_complete
    raise handshake_exc
  File "/home/proxy-server/miniconda3/lib/python3.7/asyncio/sslproto.py", line 189, in feed_ssldata
    self._sslobj.do_handshake()
  File "/home/proxy-server/miniconda3/lib/python3.7/ssl.py", line 763, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1051)
SSL error in data received
protocol: <asyncio.sslproto.SSLProtocol object at 0x7f2611d7eeb8>
transport: <_SelectorSocketTransport closing fd=10 read=idle write=<idle, bufsize=0>>
Traceback (most recent call last):
  File "/home/proxy-server/miniconda3/lib/python3.7/asyncio/sslproto.py", line 526, in data_received
    ssldata, appdata = self._sslpipe.feed_ssldata(data)
  File "/home/proxy-server/miniconda3/lib/python3.7/asyncio/sslproto.py", line 189, in feed_ssldata
    self._sslobj.do_handshake()
  File "/home/proxy-server/miniconda3/lib/python3.7/ssl.py", line 763, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1051)
[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1051)

Is this common?

Serve backward / reverse connection in Python code

I am trying to start from the example code to achieve a dynamic reverse proxy setup but having difficulty figuring out how to do it. Server is behind NAT. I need Server to connect to CentralServer. Then, CentralServer to open a port so that browser clients can tunnel through Server behind NAT:

<-- WWW <-- ServerBehindNAT <--> CentralServer <-- BrowserClient1
                                               <-- BrowserClient2

Direct API usage

I'd like to use python-proxy inline in my existing python application. It seems like I could built it up myself from pproxy, but I'd be replicating a lot of the functionality in server.main. It would be great if there was a developer friendly function pproxy that took arguments and returned a coroutine that did all the proxying.

Then the server.main would look something like:

def main():
  ...
  args = parser.parse_args()
  loop = asyncio.get_event_loop()
  loop.run_until_complete(pproxy(args))
  loop.close() 

I'm not sure if this works well w/ your architecture - but it would be very handy for my use case!

Cheers!

请教关于下载中断的问题

您好,我想请教一个下载中断的问题。
我使用python-proxy连接了我的ss服务器后,外网访问,观看视频都是没有问题的,但是在下载文件时就会遇到连接频繁被中断的情况。一般开启下载任务后,比如下载dl.google.com域名下的东西,五秒之内就完全没有速度了。
我试过Chrome和Firefox的内置下载工具,以及proxychains+wget,结果都是五秒内就完全没速度了,进而下载中断。
我确定这个并非python-proxy的问题,因为我在自己电脑和另一台电脑都试过(包括python-proxy和ss-qt5等代理工具),都出现了这种情况。操作系统都是Ubuntu的,所以我觉得问题可能是出在Ubuntu系统的配置上。
ss服务器感觉应该是没有问题的,因为我在Windows和Android下分别通过shadowsocks连接服务器,创建的下载任务都是没有任何问题的。
请问您可否给些建议?

FYI:
SS服务器在搬瓦工搭建,使用SS和锐速

我的操作系统是Ubuntu 18.04
SS使用SOCKS5
协议为CHACHA20-IETF-POLY1305

keepalive ssh

Hi,

asyncssh 1.16.0 introduced keep-alive for ssh connection. I'll draft a PR to use this functionality and change the requirements for asyncssh to enable it.

I'll probably add a function to auto re-connect if keep-alive is not working.

Cheers,

http+ssl not working

Unable to get http+ssl working.
I started the server with pproxy -i http+ssl://:8080 --ssl server.crt,server.key -v,
then configured by windows LAN setting to use secured
image

then when i try to access the page, i get "This page isn't working" on the browser. And i see no requests on the proxy server.
I created the ssl files using the commands you provided.

ipv6 issue

when i try to pproxy -l http+socks5://93.11.80.25:9005/@2a00:e60:4000:100:8000:0:f5e8:2b73#user:pass -v

it gives the following error: [Errno -6] ai_family not supported from 79.127.80.11 (this is connected client IP)

it seems server gets confused, the bind ip is IPv6 but user is getting connected through IPV4:9005.

How to rewrite request/response

Is there any examples of creating a handler that can rewrite the request or response as it passes through the proxy?

Is this something I should request on #45?

Auth for remote proxy is not working

Hi!
I'm trying to use pproxy with a remote proxy, which is a paid proxy service.
I need to authenticate the remote proxy connection with a simple http auth. Reading your docs, i understood that i need to use the username and password on the fragment part of the url, because the usual auth part on url is reserved to cyphers, right?

If i start the proxy like this: pproxy -r 'http://HOST:PORT/#USERNAME:PASSWORD' -vvv and make a call using curl --proxy "http://localhost:8080" "http://httpbin.org/ip", i receive curl: (52) Empty reply from server from the curl command.

If i do not use the pproxy and make a call using curl --proxy "http://HOST:PORT/" --proxy-user "USERNAME:PASSWORD" "http://httpbin.org/ip" works nicely.

Am i doing something wrong?

Thanks!

asynchronous proxy

Hey,

Do you have a way to run pproxy asynchronous (Thread) ?
something like:
pproxy.main(asynchronous = True)

If yes can we kill this ?
something like:
pproxy.stop()

Thx

pproxy failed for curl to connect.

Hi,

See the following test. local 1080 is a socks5 server.


$ curl -L -x socks5://127.0.0.1:1080 https://gemmei.ftp.acc.umu.se/debian-cd/current/amd64/iso-dvd/debian-10.1.0-amd64-DVD-1.iso -o /dev/null
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   394  100   394    0     0    160      0  0:00:02  0:00:02 --:--:--   160
  0 3720M    0  384k    0     0  43905      0 24:41:01  0:00:08 24:40:53 85166^C

$ pproxy -r socks5://:1080/ 
Using uvloop
Serving on :8080 by http,socks4,socks5 

$ curl -L -x socks5://127.0.0.1:8080 https://gemmei.ftp.acc.umu.se/debian-cd/current/amd64/iso-dvd/debian-10.1.0-amd64-DVD-1.iso -o /dev/null
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to gemmei.ftp.acc.umu.se:443 


Redirect to different proxies depending on auth

Hi!

I'd like to set a proxy server, over the same IP, i.e (localhost:9090), but with different authentications to redirect the traffic over one or another proxy. Let's say

http://test1:test1@localhost:9090/ will redirect to proxy http://a.b.c.d:1234 http://test2:test2@localhost:9090/ will redirect to proxy http://e.f.g.h:1235

I'm new in this, so I don't actually know if this should be done here, or in a server (apache, nginx, etc) to redirect the traffic to one or another proxy server depending on the auth

I have read the doc, but I can't find anything like it

In case it can be done straight with python-proxy , what's the way?

Thanks in advance

set rate limit for a user

is there any possibility to set rate limitation for each user ?
or set some rules inorder to prevent two devices use one account ?

pycryptodome and sshtunnel interfere with each other

As you know, asyncssh requires pycrypto to be installed. pycryptodome's documentation says:

One must avoid having both PyCrypto and PyCryptodome installed at the same time, as they will interfere with each other.

So we can't have both sshtunnel and C accelerations at the same time. Any workarounds?

Code style

I was going to try to implement #41 myself but… the code is really hard to work with. It would benefit a lot from some more newlines, and just following PEP8 in general. Even if it's just to make the linter shut up.

Would you accept a pull request if I formatted everything better?

add network throttling feature

Would you be interested in adding a plugin that does network throttling ?

That is:

  • limit the bandtwidth
  • add delays

I am using this to mimic network conditions to test browser page loads. I've implemented it using a simple port forwarder + socks5 server ar https://github.com/tarekziade/tinap

But your proxy is much better as it implements many protocols!

I guess most of the code that does this is here: https://github.com/tarekziade/tinap/blob/master/tinap/throttler.py and should be simple to refactor as a pproxy plugin

Let me know!

Run Problem ModuleNotFoundError: No module named 'fcntl'

Win10
Python 3.6.4
pproxy 1.7.3 and 1.8.5

Traceback (most recent call last):
File "c:\program files\python36\lib\runpy.py", line 193, in _run_module_as_main
"main", mod_spec)
File "c:\program files\python36\lib\runpy.py", line 85, in run_code
exec(code, run_globals)
File "C:\Program Files\Python36\Scripts\pproxy.exe_main
.py", line 5, in
File "c:\program files\python36\lib\site-packages\pproxy\server.py", line 2, in
from . import proto
File "c:\program files\python36\lib\site-packages\pproxy\proto.py", line 1, in
import asyncio, socket, urllib.parse, time, re, base64, hmac, struct, hashlib, fcntl, io
ModuleNotFoundError: No module named 'fcntl'

And install form pip also has problem:

Traceback (most recent call last):
File "setup.py", line 19, in
long_description = read('README.rst'),
File "setup.py", line 6, in read
return fp.read()
UnicodeDecodeError: 'gbk' codec can't decode byte 0x94 in position 2840: illegal multibyte sequence

This is because long_description = read('README.rst') in setup.py

DAT file support for outgoing traffic

Hi,

Do you think it's possible to write a parser for DAT files and add their configuration to pproxy for remote hosts (-r)? DAT files have their own standard formatting for host whitelisting and blacklisting so it would be a great integration

Specify only IPv4 or IPv6 Outbound

What is the handling of ipv4/ipv6 outbound from server? Is it possible to specify only ipv4 or ipv6 outbound hosts if server has both ipv4 and ipv6 address?

config file draft

Hi, here's a very basic config file template designed to work with pproxy. I'm open for all sorts of feedback and improvement as this probably covers ~60 percent of what pproxy offers.

{
    "general":{
        "block":{
            "enabled": true,
            "type": "path_list/regex_list",
            "values": [
                "1.1.1.1/24",
                "2.2.2.2/24",
                "in case of path_list => /path/to/the/file1",
                "in case of path_list => /path/to/the/file2"
            ]
        },
        "check_alive":{
            "enabled": true,
            "interval": 30
        },
        "schedule":{
            "enabled":true,
            "algorithm": "fa"
        },
        "pac":{
            "enabled": true,
            "path": "asdasds"
        },
        "sys":{
            "enabled": true
        },
        "test":{
            "enabled": true,
            "path": "http://ident.me"
        }

    },
    "servers":[
            {
                "enabled": true,
                "name": "SERVER1",
                "type": "in/out",
                "addr": "0.0.0.0",
                "port": "80",
                "unix_socket": "/tmp/myproxy",
                "inverse": false,
                "http_settings":{
                    "enabled": true,
                    "disable_http_connect": true,
                    
                    "auth": {
                        "enabled": true,
                        "creds": [
                            "user1:pass1",
                            "user2:pass2"
                        ]
                    },
                    "ssl": {
                        "enabled": true,
                        "type": "base64/path/insecure",
                        "cert": "asdasdasd",
                        "key": "asdasdasd"
                    }
                },
                "socks_settings":{
                    "enabled":true,
                    "version": "4/5/4+5",
                    "auth": {
                        "enabled": true,
                        "creds": [
                            "user1:pass1",
                            "user2:pass2"
                        ]
                    },
                    "ssl": {
                        "enabled": true,
                        "type": "base64/path/insecure",
                        "cert": "asdasdasd",
                        "key": "asdasdasd"
                    }                  
                },
                "ss_settings":{
                    "enabled": true,
                    "password": "123",
                    "cipher": "aes-256-gcm",
                    "ssl": {
                        "enabled": true,
                        "type": "base64/path/insecure",
                        "cert": "asdasdasd",
                        "key": "asdasdasd"
                    }
                },
                "ssr_settings":{
                    "enabled":true,
                    "password": "123",
                    "cipher": "aes-256-gcm",
                    "plugins":{
                        "enabled": true,
                        "values":[
                            "plain",
                            "origin",
                            "http_simple",
                            "tls1.2_ticket_auth",
                            "verify_simple",
                            "verify_deflate"
                        ]
                    }
                },
                "redir_settings":{
                    "enabled": true
                },
                "tunnel_settings":{
                    "enabled": true,
                    "hosts": ["www.google.com"]
                },
                "ssh_settings":{
                    "enabled": true,
                    "remote_host": "1.2.3.4",
                    "remote_port": 22,
                    "cred_type": "password/key_path/key_base64",
                    "username": "root",
                    "cred": "whatever"
                },
                "ws_settings":{
                    "enabled": true,
                    "ssl": {
                        "enabled": true,
                        "type": "base64/path/insecure",
                        "cert": "asdasdasd",
                        "key": "asdasdasd"
                    }
                }                
            }     
        ]
}

Statically linked binary release

Hi, I managed to get a working statically linked binary for pproxy here. Do you think it's advisable to put that binary in the release section of the project? It works very well and doesn't depend on system's Python version. Most older Linux distros don't have python 3.6 so the binary will work just fine

transparent proxy for http and https

Hi,
I want a transparent proxy for http and https. At the moment i think there is a feature missing.

Setup:
Linux Laptop
2 Networks

  • Home network direct internet access
  • Corporate network internet access only through proxy

So i want that pproxy uses a proxy if proxy is alive otherwise fall back to direct connections.

Redirect all my local traffic to pproxy via iptables:
iptables -t nat -A OUTPUT -p tcp -m owner ! --uid-owner proxy --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A OUTPUT -p tcp -m owner ! --uid-owner proxy --dport 443 -j REDIRECT --to-port 8080

pproxy -l redir://:8080/ -r http://142.93.135.90:8080 -a 3 -vv

Start as user and group "proxy" (so that direct connections will work)
Redirect traffic to upstream proxy (corporate)
Try if alive in a 3 second interval
Verbose to check whats going on

Problem:
Tests:

curl -I http://seamex.de
curl: (8) Weird server reply
curl -I https://seamex.de
HTTP/2 200 ...

Looks like just the https traffic is redirected. Can you please fix that :)
https and http traffic needs to be redirected to the upstream proxy (i also tried auto detection like: redir+http but that dont work)

Workaround:
I installed redsocks that listens on two ports one for http and one for https to do the different connect methods (http-relay, http-connect). Redsocks upstreams to pproxy (as http started). But i dont want to use two proxies when one can handel that ;)

bug in providing ipv6 binding (SOCKS)

when running proxy with the following arguments socks gives this error: getsockaddrarg() takes exactly 2 arguments (4 given) from 95.X.X.X

pproxy -l http+socks5://93.X.X.X:9000/@00:e:0:0:0:0:edaf:80ef#user:pass -v

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.