用Python写的socks5代理及其分支

原文:http://igfw.net/archives/10294

小虾是个好同学,以前介绍过其用Python写的VPN程序udpip,据说WCProxy最初也是其用Python写成的,这次要介绍的是其用Python写的socks5代理及其分支。

好吧上Python写的socks5服务器端代码(来源):

import socket, sys, select, SocketServer, struct, time          class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): pass        class Socks5Server(SocketServer.StreamRequestHandler):            def handle_tcp(self, sock, remote):                fdset = [sock, remote]                while True:                    r, w, e = select.select(fdset, [], [])                    if sock in r:                        if remote.send(sock.recv(4096)) <= 0: break                    if remote in r:                        if sock.send(remote.recv(4096)) <= 0: break            def handle(self):                try:                    print 'socks connection from ', self.client_address                    sock = self.connection                    # 1. Version                    sock.recv(262)                    sock.send(b"\x05\x00");                    # 2. Request                    data = self.rfile.read(4)                    mode = ord(data[1])                    addrtype = ord(data[3])                    if addrtype == 1:       # IPv4                        addr = socket.inet_ntoa(self.rfile.read(4))                    elif addrtype == 3:     # Domain name                        addr = self.rfile.read(ord(sock.recv(1)[0]))                    port = struct.unpack('>H', self.rfile.read(2))                    reply = b"\x05\x00\x00\x01"                    try:                        if mode == 1:  # 1. Tcp connect                            remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)                            remote.connect((addr, port[0]))                            print 'Tcp connect to', addr, port[0]                        else:                            reply = b"\x05\x07\x00\x01" # Command not supported                        local = remote.getsockname()                        reply += socket.inet_aton(local[0]) + struct.pack(">H", local[1])                    except socket.error:                        # Connection refused                        reply = '\x05\x05\x00\x01\x00\x00\x00\x00\x00\x00'                    sock.send(reply)                    # 3. Transfering                    if reply[1] == '\x00':  # Success                        if mode == 1:    # 1. Tcp connect                            self.handle_tcp(sock, remote)                except socket.error:                    print 'socket error'        def main():            server = ThreadingTCPServer(('', 1080), Socks5Server)            server.serve_forever()        if __name__ == '__main__':            main()

直接运行这个程序就给本机建立了一个socks5的代理服务器(需要Python2.6以上版本才能运行)。

就这么简单,无论你看懂没看懂,反正我是不懂Python代码。

好吧那发一个某人自用了一年多的翻墙工具 shadowsocks 吧,这个shadowsocks就是根据上面的代码修改的,这个用 Python 写的 socks 加密代理,加密方法很简单,不过欺骗 GFW 足够了。 shadowsocks作者说;“当初激发我写这个东西的原因是 ssh tunnel 容易断,每次重连会卡一段时间,并且并发能力有限。于是用普通的 socket server,来一个连接建一个连接。到现在用了一年多,感觉挺稳定,不如发布出来吧。
”。

shadowsocks项目地址https://github.com/clowwindy/shadowsocks

使用方法:

Put server.py on your server. Edit server.py, change the following values:

PORT server port   KEY a password to identify clients 

Run python server.py on your server. To run it in the background, run setsid python server.py.

Put local.py on your client machine. Edit local.py, change these values:

SERVER your server ip or hostname   REMOTE_PORT server port PORT local port   KEY a password, it must be the same as the password of your server 

Run python local.py on your client machine.

Change proxy settings of your browser into

SOCKS5 127.0.0.1:PORT 

我没有测试过这个程序,我测试的是balan-proxy程序。balan-proxy程序fork自shadowsocks。没修改什么,就用生成器循环返回服务器地址,增加对多个服务端的支持,如果在限制带宽的内网使用,可达到多倍带宽的效果。在下载http资源,及播放在线视频时有显著加速功能。

balan-proxy项目地址https://github.com/lerry/balan-proxy

增加自定义服务器列表支持,请将服务器地址列表放在同文件夹下,文件名: list.txt 格式:
8.8.8.8:8499
4.4.4.4:8499
#1.1.1.1:8849
暂时不使用的服务器地址可使用#注释

用法和shadowsocks一样( 装gevent,然后在启动server.py,能省下一些内存)。

不过上面代理加密简单,如果要高强度的加密可以考虑换成两边用ssl来通信,这就有了sockstunnel,sockstunnel是一个使用ssl加密隧道的简单 socks5服务器(shadowsocks也在测试更强的加密方式)。

sockstunnel项目地址https://github.com/wynemo/sockstunnel

在服务器上,使用 openssl 生成您的密钥和证书文件的方法

openssl genrsa -out privkey.pem 2048   openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095

作者说其在server:ubuntu 11.10 x64 python2.7 /client:windows7 python 2.7.3,ubuntu 11.10 python 2.7.2下测试成功,有兴趣的可以试试。

除了加密问题,还有人提出了IPv6支持问题,于是shadowsocks作者加了一个实验性的 IPv6 branch,Server 是 IPv6 地址,因为和 IPv4 不兼容,所以暂时没合并。

IPv6 branch项目地址https://github.com/clowwindy/shadowsocks/tree/ipv6

shadowsocks作者折腾完Python版后又把目光瞄向了node.js,这就有了加密代理 shadowsocks node.js 版。作者说加密代理 shadowsocks node.js 版经过一个多月的改进现在可以在 1000 并发,500 QPS 下稳定工作。现在用在一个项目中,每天通过上百 GB 流量。

shadowsocks-nodejs项目地址https://github.com/clowwindy/shadowsocks-nodejs

和原 Python 版相比优势:
1. 不会大量创建线程,VSZ 使用很少,适合 OpenVZ。
2. 支持更大并发。因为 Python 版用的是 select(),fd > 1024 的时候就挂了。

缺点:
下载大文件时内存占用峰值会达到几十 MB,怀疑与 V8 的 GC 策略有关。(参考)
当然 Python 版也可以改用非阻塞模型,不过写起来比 nodejs 麻烦就是了。欢迎有兴趣的童鞋做这样的尝试 :)

说明:
如果都升到最新版,Python 版与 node.js 版的协议是互相兼容的。即可以用 python client + node.js server。
另外感叹 V8 的性能确实很好,基本相同的计算密码表过程,纯 js 实现比纯 Python 实现快了几十倍。

使用方法:

Edit config.json, change the following values:

server your server ip or hostname   server_port server port   local_port local port   password a password used to encrypt transfer   timeout in seconds 

Put all the files on your server. Run node server.js on your server. To run it in the background, run setsid node server.js.

Put all the files on your client machine. Run node local.js on your client machine.

Change proxy settings of your browser into

SOCKS5 127.0.0.1:local_port 

另外作者还将多 server 功能加到一个新分支里了。

multi-server branc项目地址https://github.com/clowwindy/shadowsocks-nodejs/tree/multi-server

50多行代码引起了这许多故事,终究使用起来还是要比ssh代理速度快,有VPS的同学可以试试啦。

另外以前说过goagent在1.9.1a2测试版本中加入使用ssl加密独立主机上的wsgi.py(使用方法:python wsgi.py 443 -ssl ),这个和上面介绍的也是殊途同归,不过goagent貌似也开始独立主机上的socks5代理了。

本文原始地址http://igfw.net/archives/10294

发表评论