Pages

Friday, 29 June 2012

利用shadowsocks(SERVER.PY版): BALAN-PROXY翻墙,这是最简单/省事的翻墙术


CLOWWINDY最早的SHADOWSOCKS(此版已被作者CLOWWINDY删除),不过它有一个FORK版:balan-proxy (https://github.com/lerry/balan-proxy/)

登录你的vps,
git clone https://github.com/lerry/balan-proxy/
cd balan-proxy
编辑balan-proxy目录里的server.py如下:
...
PORT = 8499 (这个是balan-proxy的端口号,保持默认的8499,不必修改)
KEY = "你自行设置的一个字符串"注意:这里的引号不可缺少。需跟本地的local.py里的KEY值一致)
...
然后运行命令:python server.py
此命令是运行在前台的。我们可以利用systemd把它运行为service:
nano /etc/systemd/system/balan-proxy.service
cat /etc/systemd/system/balan-proxy.service
[Unit]
After=network.target

[Service]
ExecStart=/usr/bin/python /root/balan-proxy/server.py
Restart=always

[Install]
WantedBy=multi-user.target

然后运行:
systemctl start balan-proxy
systemctl enable balan-proxy
服务器端搭建完成。
(当然你的vps需先安装python:
apt-get install python -y或yum install python -y)

回到本地linux桌面系统机器,
下载源码:https://github.com/lerry/balan-proxy/archive/master.zip。
解压,进入解压出来的目录,编辑里面的local.py文件如下:
...
SERVERS = [
      ('你的vps的ip', 8499),
    ]
...
PORT = 10802 #这个是要设置的本地端口,你可以修改它为其他端口。
KEY = "你自行设置的一个字符串"注意:这里的引号不可缺少。这个KEY值需跟你vps上设置的KEY值一致)
...
运行nohup python local.py > /dev/null &
然后设置你的浏览器的socks5代理为127.0.0.1,端口为10802,即可翻墙。

如果你的本地机器为mac.
git clone https://github.com/lerry/balan-proxy
cd balan-proxy
编辑里面的local.py文件如下:
...
SERVERS = [
      ('你的vps的ip', 8499),
    ]
...
PORT = 10802 #这个是要设置的本地端口,你可以修改它为其他端口。
KEY = "你自行设置的一个字符串" 注意:这里的引号不可缺少。这个KEY值需跟你vps上设置的KEY值一致)
...

然后,运行python local.py
(不要关闭该terminal窗口)
然后设置你的浏览器的socks5代理为127.0.0.1,端口为10802,即可翻墙。
在mac上,可通过launchd实现开机自运行命令python local.py,操作流程如下:
cd ~/Library/LaunchAgents/
nano com.balan-proxy.plist
内容为:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>com.balan-proxy</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/python</string>
<string>~/balan-proxy/local.py</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>

</plist>

然后运行launchctl load com.balan-proxy.plist
这样,即可实现开机自运行命令python local.py

如果你的本地机器为windows,
则在你的本地windows机器上安装python2.7.3环境: http://www.python.org/ftp/python/2.7.3/python-2.7.3.msi,python2.7.2有问题,建议卸载python2.7.2,安装python2.7.3,然后就可以运行local.py(即双击local.py),会弹出一个 dos窗口,不要关闭该窗口。然后设置你的浏览器的socks5代理为127.0.0.1,端口为10802,即可翻墙.

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

为防止balan-proxy的作者删除源码,特在此把local.py文件的内容和server.py文件的内容保存如下。
附录:
local.py文件的内容:
#!/usr/bin/env python
# Copyright (c) 2012 clowwindy
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import os
SERVERS = [
('xxx.xxx.xx.11', 8499),
]
if os.path.exists('list.txt'):
data = open('list.txt').readlines()
SERVERS = []
item = (i.split(':') for i in data if ':' '#' not in i)
while 1:
try:
i = item.next()
except:
break
SERVERS.append((i[0], int(i[1])))
PORT = 1080
KEY = "foobar!"
import sys
import socket
import select
import string
import struct
import hashlib
import threading
import time
import SocketServer
def get_server():
servers = SERVERS
while 1:
for i in servers:
yield i
server = get_server()
def get_table(key):
m = hashlib.md5()
m.update(key)
s = m.digest()
(a, b) = struct.unpack('<QQ', s)
table = [c for c in string.maketrans('', '')]
for i in xrange(1, 1024):
table.sort(lambda x, y: int(a % (ord(x) + i) - a % (ord(y) + i)))
return table
encrypt_table = ''.join(get_table(KEY))
decrypt_table = string.maketrans(encrypt_table, string.maketrans('', ''))
my_lock = threading.Lock()
def lock_print(msg):
my_lock.acquire()
try:
print "[%s] %s" % (time.ctime(), msg)
finally:
my_lock.release()
class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
class Socks5Server(SocketServer.StreamRequestHandler):
def encrypt(self, data):
return data.translate(encrypt_table)
def decrypt(self, data):
return data.translate(decrypt_table)
def handle_tcp(self, sock, remote):
try:
fdset = [sock, remote]
counter = 0
while True:
r, w, e = select.select(fdset, [], [])
if sock in r:
r_data = sock.recv(4096)
if counter == 1:
try:
lock_print(
"Connecting " + r_data[5:5 + ord(r_data[4])])
except Exception:
pass
if counter < 2:
counter += 1
if remote.send(self.encrypt(r_data)) <= 0:
break
if remote in r:
if sock.send(self.decrypt(remote.recv(4096))) <= 0:
break
finally:
remote.close()
def handle(self):
try:
host = server.next()
sock = self.connection
remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote.connect(host)
self.handle_tcp(sock, remote)
except socket.error:
lock_print('socket error')
def main(host):
print 'Starting proxy at port %d' % PORT
server = ThreadingTCPServer((host, PORT), Socks5Server)
server.serve_forever()
if __name__ == '__main__':
print 'Servers: '
for i in SERVERS:
print i
arg = sys.argv
if len(arg) == 1:
host = ''
print "Use default host"
else:
host = arg[1]
print "Use host %s" % host
main(host)
server.py文件的内容:
#!/usr/bin/env python
# Copyright (c) 2012 clowwindy
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
PORT = 8499
KEY = "foobar!"
import sys
import socket
import select
import SocketServer
import struct
import string
import hashlib
def get_table(key):
m = hashlib.md5()
m.update(key)
s = m.digest()
(a, b) = struct.unpack('<QQ', s)
table = [c for c in string.maketrans('', '')]
for i in xrange(1, 1024):
table.sort(lambda x, y: int(a % (ord(x) + i) - a % (ord(y) + i)))
return table
class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
class Socks5Server(SocketServer.StreamRequestHandler):
def handle_tcp(self, sock, remote):
try:
fdset = [sock, remote]
while True:
r, w, e = select.select(fdset, [], [])
if sock in r:
if remote.send(self.decrypt(sock.recv(4096))) <= 0:
break
if remote in r:
if sock.send(self.encrypt(remote.recv(4096))) <= 0:
break
finally:
remote.close()
def encrypt(self, data):
return data.translate(encrypt_table)
def decrypt(self, data):
return data.translate(decrypt_table)
def send_encrpyt(self, sock, data):
sock.send(self.encrypt(data))
def handle(self):
try:
print 'socks connection from ', self.client_address
sock = self.connection
sock.recv(262)
self.send_encrpyt(sock, "\x05\x00")
data = self.decrypt(self.rfile.read(4))
mode = ord(data[1])
addrtype = ord(data[3])
if addrtype == 1:
addr = socket.inet_ntoa(self.decrypt(self.rfile.read(4)))
elif addrtype == 3:
addr = self.decrypt(
self.rfile.read(ord(self.decrypt(sock.recv(1)))))
else:
# not support
return
port = struct.unpack('>H', self.decrypt(self.rfile.read(2)))
reply = "\x05\x00\x00\x01"
try:
if mode == 1:
remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote.connect((addr, port[0]))
local = remote.getsockname()
reply += socket.inet_aton(local[0]) + struct.pack(">H",
local[1])
print 'Tcp connect to', addr, port[0]
else:
reply = "\x05\x07\x00\x01" # Command not supported
print 'command not supported'
except socket.error:
# Connection refused
reply = '\x05\x05\x00\x01\x00\x00\x00\x00\x00\x00'
self.send_encrpyt(sock, reply)
if reply[1] == '\x00':
if mode == 1:
self.handle_tcp(sock, remote)
except socket.error:
print 'socket error'
def main(host=''):
server = ThreadingTCPServer((host, PORT), Socks5Server)
server.allow_reuse_address = True
print "starting server at port %d ..." % PORT
server.serve_forever()
if __name__ == '__main__':
encrypt_table = ''.join(get_table(KEY))
decrypt_table = string.maketrans(encrypt_table, string.maketrans('', ''))
arg = sys.argv
if len(arg) == 1:
host = ''
print "Use default host"
else:
host = arg[1]
print "Use host %s" % host
main(host)
---------------------------------------------------------------------
balan-proxy程序fork自shadowsocks。
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
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 ),这个和上面介绍的也是殊途同归
---------------------
用polipo把socks代理转换为http代理也很好用.把socks代理转换为http代理的最大好处就是
可以避免dns污染,比如你使用IE并且设置ie的socks代理的话,你依然是打不开
dongtaiwang.com的;但是如果你使用IE并且设置ie的http代理的话,
这样你就可顺利打开dongtaiwang.com (建议使用polipo,privoxy有时会出错。
polipo的使用方法:
http://web.archive.org/web/20130524201431/http://www.iusesoft.info/using-polipo-to-make-opera-works-with-socks5,)
不建议把此shadowsocks(它是一个socks proxy)搭配sockscap使用,因为通过ie还是打不开dongtaiwang.com

related post: 
http://briteming.blogspot.com/2012/07/sockstunnel.html(利用sockstunnel翻墙) 
http://briteming.blogspot.co.uk/2012/07/proxifierssh.html
http://briteming.blogspot.co.uk/2012/06/blog-post_20.html 
------------------------
 
shadowsocks(SERVER.PY版)的改进版

usage

First, make sure you have Python 2.6 or 2.7.
$ python --version
Python 2.6.8
Then edit config.json as follows:
{
    "server":"your_vps_ip",
    "server_port":8086,
    "local_port":1030,
    "password":"你自设的密码",
    "timeout":600
}
(注意:在该版本中,不要在上面的配置文件里加上"method":"aes-256-cfb",否则翻墙速度会变慢)
Put all the files on your server. Run python server.py on your server. To run it in the background, run nohup python server.py > log &.
Put all the files on your client machine. Run python local.py on your client machine.
Change proxy settings of your browser into
SOCKS5 127.0.0.1:local_port

advanced

You can use args to override settings from config.json.
python local.py -s server_name -p server_port -l local_port -k password
python server.py -p server_port -k password
You may want to install gevent for better performance:
$ apt-get install python-gevent
Or:
$ sudo easy_install gevent

troubleshooting

  • I can only load some websites Check the logs of local.py. If you see only IPs, not hostnames, your may got DNS poisoned, but your browser hasn't been configured to let the proxy resolve DNS. To set proper DNS config, you can simply install FoxyProxy / Autoproxy for Firefox, or ProxySwitchy / SwitchySharp for Chrome. They will set the config in your browser automatically. Or you can change network.proxy.socks_remote_dns into true in about:config page if you use Firefox.
  • I can't load any websites and the log prints mode != 1 Make sure proxy protocol is set to Socks5, not Socks4 or HTTP.
  • I use IE and I can't get my proxy to work Since you can't specify Socks4 or Socks5 in IE settings, 
  • you may want to use a PAC(Proxy auto-config) script, or just use Firefox instead.
from https://github.com/YvesChan/shadowsocks
shadowsocks 原理是借助国外的 VPS 翻墙。国外的 VPS 上运行服务端,在本地运行本地端,就可以建立加密连接。 用文本编辑器编辑 config.json,请注意一定要修改密码。 server 你的 VPS 的地址 server_port 使用的服务端口 local_port 本地 socks5 端口 password 请设置一个你的密码 用winscp 上传 server.py 和 config.json 到 VPS 上的某个目录。如果是 root 用户,放到 /root/ 下;如果是其他用户,放到 /home/用户名 目录下。 用putty 登录到 VPS。 安装 python: Debian, Ubuntu: sudo apt-get install python CentOS: yum install python (其实大部分LINUX VPS已默认安装了PYTHON) cd 进入到上传的目录,运行(注意后面的 &): nohup python server.py > /dev/null & 退出 putty。接下来只要 VPS 没有重启,服务端会一直运行下去。 在本地的windows机器运行 local.exe 修改浏览器的代理设置。使用 SOCKS5 代理,地址为 127.0.0.1:刚才设置的本地socks5端口。 最简单的方法是:建一个 Chrome 的快捷方式,右键,属性,在目标的最后加上: --proxy-server=socks5://127.0.0.1:所设置的本地端口。 推荐 Firefox 配合 Autoproxy 使用,Chrome 配合 SwitchySharp 使用,
可以根据网址自动选择是否翻墙。注意使用的时候,代理协议要选择 SOCKS5
(而不是 SOCKS4 或者 HTTP)。 IE浏览器使用 SOCKS5代理,需要配合 PAC 文件,
不推荐使用。 如果哪天你翻墙失败, 那么可能是 nohup python server.py > /dev/null &所对应的python进程退出了。你可运行命令: lsof -i:所使用的服务端口号 或 netstat -anp|grep 所使用的服务端口号 查看一下有无进程在使用该端口。如果没有进程在使用该端口,说明 nohup python server.py > /dev/null &所对应的python进程退出了,需要在VPS中,
重新运行一次该命令:nohup python server.py > /dev/null & 如果你想创建账号给某人使用,可这样做: 登录VPS, nano config.json 在这一步修改server_port和password的值. 下载地址: https://cloud.github.com/downloads/clowwindy/shadowsocks-win32pack/shadowsocks.7z 以上内容适用于WINDOWS桌面系统。
-------------------------
 
https://github.com/mengskysama/shadowsocks-rm/tree/master/shadowsocks
--------------------------
 
因为BALAN-PROXY没有加密,有时翻墙速度较慢。它不如sockstunnel的翻墙速度快。
sockstunnel: http://briteming.blogspot.com/2012/07/sockstunnel.html 
-----------------------------
https://github.com/li-plus/secure-socks,这个翻墙项目也是没有加密的。