2009年7月28日星期二

组合翻墙方案

1.墙的存在和原理简述
1.1.墙的存在
    在您访问某些网站的时候,经常会发现无法访问。通常来说,这是服务器挂了。但是现在,越来越多正常的服务器出现了无法访问的情况。这些服务器中有一些是因为色情和暴力问题,但是更多则是政治层面的因素,例如google和twitter。对于用户来说,可能不关心政治层面的因素。但是政治自然的关心了你,所以我们需要找一种方法,让我们依然能够使用网络上一些很重要的服务。例如gmail(本文即是在gmail中写成的)。本节中,我将简述国家网络防护工程(简称GFW, Great FireWall)的工作原理,并在下一节给出一些比较成熟的翻墙方案。
1.2.DNS污染
    我们通过DNS(Domain Name Service)将域名转换为IP地址。通常而言,我们不会怀疑ISP的DNS服务器的可信性。然而在某些地方,DNS服务器被用来欺骗客户端,达到屏蔽的作用。例如,在上海的某些地方,fanfou.com曾经被指向127.0.0.1。如果机器按照这个地址访问,那么肯定无法获得预想的数据。
    这个方案如果控制不当,可能造成全球性的后果。曾经有报道,伊朗将youtube的域名指向了自己的一台蜜罐(Honeypot)服务器。但是由于配置不良,因此DNS错误被扩散到了伊朗以外,导致全世界的youtube访问都被定向到了这台蜜罐。整个过程造成了youtube6小时以上的服务中断。
1.3.DNS替换欺骗
    由于DNS污染会被下面2.1节的方法绕过,因此在某些地方针对OpenDNS的数据被进行了替换欺骗。UDP53端口的查询数据包被拦截和替换,其造成的结果就是即使使用了OpenDNS,返回结果和电信服务器的结果仍然一致。
1.4.IP禁止
    对于某些IP,防护系统直接禁止了该IP的访问。这种手法一般见于早期,由于经常导致误杀和株连,同时对最普通的proxy都无效,因此现在已经不常使用。
1.5.关键词过滤
    防护工程在中国网络的核心路由器上,都放置了一些探头。具体的方法为配置一个核心路由器的镜像端口,将所有通讯数据全部向端口转发一份。该端口指向一套深度包检测集群。如果数据没有异常,则不对通讯进行干扰。如果数据异常,则发送RST包拦截通讯。同时记录双方IP,拦截其后5分钟内的所有TCP SYN包。
    这种方法的优势在于,无论多复杂的网络拓扑结构。只要能够开镜像端口,就可以工作。无论多大的规模和多高的流量,只要能添加服务器,就可以支持。同时由于屏蔽效果好,对普通访问的干扰小,因此目前已经成为最主要的屏蔽方式。
    这种手法无法针对UDP工作,因为UDP不存在链接断开状态。同时如果双方都屏蔽RST包,则连接不会被中断。然而如果双方都屏蔽RST包,会导致一些主动断线在对方那里变成死连接,因此无法通过拦截RST包来防御。同时,按照当前的测试结果,IPv6的包并没有被拦截。相信这是因为核心路由器支持了IPv6,但包检测集群尚未支持IPv6包检测。
1.6.热点屏蔽
    近来发现一种趋势,当某个链接的热度非常高的时候,通向此链接的访问会被屏蔽。由于是接受到RST包,因此不像是服务器超载。这是当前防护系统的新方向,尚没有更多资料。
2.翻墙方法简述
2.1.OpenDNS
    DNS污染可以通过修改自己的DNS服务器来屏蔽。以Linux为例,当前你的DNS服务器配置可以在/etc/resolv.conf中查看。你可以将其替换为OpenDNS的DNS服务器,而非电信的服务器。OpenDNS是一家商业公司,通过提供DNS服务来收费(不具体解释商业运作)。一般来说,他们的DNS服务还是比较准确的。
    通过OpenDNS可以防御DNS污染,但是无法防御其余方式,而且会被DNS替换所干扰。因此建议一般作为常规网络配置,而非专门的翻墙方案。
2.2.hosts
    hosts的目地和OpenDNS一致,但可以防御DNS替换。其原理是通过将正确的DNS结果写入/etc/hosts文件,在绕过网络解析过程。从而避免DNS出错。
    该方式无法防御1.4-1.6的屏蔽。
2.3.proxy和变形
    针对DNS欺骗和IIP屏蔽,我们可以通过指定一个国外的代理来访问。由于DNS解析在代理商进行,因此一般不会被欺骗。由于不直接访问IP,因此IP屏蔽也失效。
    一般而言,该方法无法屏蔽1.5的屏蔽,但是有一些变形产品(例如Firefox的gladder插件),通过变形URL请求,使用特殊代理的方式对1.5进行了部分绕过。但此种方式不保证100%成功。
2.4.ssh -D
    ssh是一种安全的远程命令行工具,具有很多端口转发选项。其中有一种动态端口转发选项,在服务器端开启后,使得ssh可以被作为一个socks5代理服务器使用。
    此种方式需要有一个墙外的ssh服务器,一般可以购买墙外的空间,他们会附送一个。此种方式可以绕过全部屏蔽方式,但是由于ssh本身的稳定性,因此经常有掉线的问题。而且有的服务器关闭了动态性转发选项,或者对长期连入的ssh连接进行断线处理。同时,由于很多人接入同一个IP进行翻墙,因此很多网站(例如google)会认为你的访问不可信。
2.5.tor
    tor是一种分布式代理工具,可以在隐蔽源和目标的情况下访问服务器。该方法可以绕过所有屏蔽方式,但是通常而言,该方法的访问会比较慢。同时也存在访问不可信的问题。
2.6.gae
    gae是google的个人引擎服务,一般由很多服务器构成,而这些服务器一般位于国外。有人针对这个特点,制作了特殊的python程序,能够将客户的访问转换成特殊的加密包,在服务器上访问目标服务器。因此可以被视为一种特殊的代理协议。该方法可以绕过所有屏蔽方式,但是由于众所周知的原因,gae服务器本身有的时候也会被屏蔽,导致该方法无法工作。而且由于google本身的屏蔽,该方式对于某些网站也是无法访问的。该方式也存在访问不可信的问题。
2.7.vpn
    vpn是唯一一种能够快速有效,一劳永逸的翻墙方式。使用vpn后,等同于你的机器拉了根线接在国外的网络端口上。因此该方法可以穿越所有屏蔽方式,同时很少有访问不可信的问题。唯一的问题是vpn,尤其是快速的vpn很难得,而且通常很贵。
3.组合翻墙
3.1.问题
    纵观全部翻墙方式,每种方式都有一定的缺陷。2.1-2.3并不总有效,ssh不稳定,tor慢,gae看运气,vpn又贵。同时,我们还要借助终端的客户端组件(foxyproxy之类)来区分被屏蔽的网站和普通网站(使得普通网站的访问不使用特殊的方式)。
3.2.目标
    本文试图通过某种方法,同时使用2.4-2.6的一种或多种方法。达到访问透明,使用稳定,速度尽量快,流量尽量小的目标。
3.3.架构
    我们使用squid和haproxy进行代理调度,达到上述目标。squid是一种老牌的开源代理服务器,其特征是会对代理内容进行缓存,减小访问流量。同时,可以将请求转发到其他代理上。从而会自动检测和管理多种代理服务器。haproxy是一种基于tcp和http的反向代理程序,在此我们需要使用它的TCP代理能力,将多种socks5代理集成为一个。
基本架构图如下:
                                                      /       -> tor
web brower -> squid -> privoxy -> haproxy -> sshtunnel
                        \     -> gappproxy
3.4.优势
    相对单层代理,组合方式具有多个优势。
    使用squid分离访问线路,并缓存访问数据。对大规模密集访问,可以有效的减小流量。而且对除Firefox外的浏览器,可以根据其访问范围控制代理线路,进一步减小代理流量。(Firefox可以使用AutoProxy或FoxyProxy)
    使用haproxy反向代理了socks5服务,因此可以并行使用多个sshtunnel的带宽。同时自动检测这些ssh是否可用,保证了访问的连续,同时也非常容易添加和减少代理。
3.5.劣势
    本方法有一个比较明显的问题,即squid无法直接使用socks5代理,因此需要通过privoxy进行转换和保密。但是此时squid只测试privoxy的存活,而不理会socks5的存活。因此当haproxy的后端全部失效的时候,squid仍旧会认为privoxy有效,进而导致出现privoxy的错误页面。
    同时,由于haproxy只检测ssh端口是否相应。因此当远程服务器几乎不响应代理请求时,haproxy并不会将这一代理移除出列表。从而导致某些请求需要非常长的时间完成。
3.6.适用范围
    本方式在完成设置后,可以稳定,快速,小流量的访问所有网站。客户端无需过多的设置。但是服务设置过于复杂,系统庞大,多数时候还需要一台专门的Linux。相对而言,这种方法更适合于3-5人以上,同时需要翻墙的情况。通过一台专门的虚拟服务器作为代理,可以顺利的让多人同时使用国际网络。
4.一个实现
4.1.基本系统
    debian stable,aptitude install squid3 squid3-cgi lighttpd tor privoxy haproxy。
4.2.gappproxy
    针对gappproxy项目,请自行去其主页上查看服务器组建方式。作为本次成果之一,贝壳封装了一个gappproxy的deb包。修改了部分源码,并形成了服务。需要的用户可以下载gappproxy-1.0.0beta_all.deb包,安装并修改配置文件即可直接使用。
4.3.sshtunnel的封装
    一般而言,我们使用ssh -D来开启sshtunnel。但是这样做有几个缺陷。首先是tunnel无法跟随系统启动,其次是由于tty关闭后程序一同关闭,因此往往需要screen或nohug来保持连接,最后是ssh往往容易意外关闭,导致需要手工重启。
    贝壳针对这种情况,包装了一套脚本,并形成sshtunnel_1.0.0beta_all.deb包。需要的用户可以下载并修改配置。服务启动后即一直运行,关闭后会自动重启。
5.远景目标
    上述系统安装的细节并未详述,同时,对于新手也太过复杂。因此,考虑实现一套完整的最小虚拟机,提供完整的上述功能。并且给出一套界面,使得用户可以方便的配置和操作整个代理系统。

2009年7月14日星期二

地铁二号线今天大规模停运&生日

    今天早上,贝壳沿着地铁四号线到世纪大道准备换乘二号线的时候,发现车站内有大量人员滞留。六号线卷门不开,二号线站台堆满人。地铁方面广播,二号线故障,暂时停开,恢复时间不定。因此贝壳无奈,只好上地面去方法。
    贝壳先是在世纪大道上找出租,不过大家可以想象,这是徒劳的。而后去公交站,发现——我实在不想经历那种密度。最后,走到杨高路,和几个人合打了一部车,从杨高路走龙阳路到张江。结果,又很无奈的发现,龙阳路堵车。最后,花了50多,在11点的时候总算到了张江。
    真是良好的生日的开端,希望我下一年不要这么倒霉。电脑诸神啊,赐我一个女友吧。不会C++也好,不用Linux也行,只要她别用Windows,而且还不怎么会用。Enter。

游婺源

    写这么多年blog,每次都当回事情,实在写的太累了。还是简单一点,不要费劲了,想到哪里,写到哪里吧。
    简单来说,有朋友家在婺源,我过去玩了一次。地方不错,好山好水,绿茶不错。记得冬天去,夏天昆虫多,草也多。一个朋友给叮肿了一圈,另一个活像被鞭打过。而且太阳太大,一个成了活包公,贝壳回来褪了层皮。
    另外,如果当地人告诉你,不远,不可怕,很好玩,不要随便相信。他们倒是不会害你,只是他们的标准和你的不大一样。超过60度的斜坡,连爬一个多小时,只是一个稍微有点累的常规路途而已。因此,如果你没有一定的体力和运动上的自信,不要随便和当地人去走小道。小道这东西有两个坏处,一个是走到一半不能回头,另外一个就是随时可能找不着或者被修路修掉滑坡断掉。
    好吧,有意的话联系我。

2009年7月7日星期二

ssh翻墙服务

    不多说了,上脚本。
-----------/etc/init.d/sshtunnel------------
#!/bin/bash

PATH=/bin:/sbin:/usr/bin:/usr/sbin
CONF="/etc/default/sshtunnel"
source $CONF

if ! [ -x /usr/bin/ssh ]; then
        exit 0
fi

start ()
{  
    echo -n "Starting tunnel.."
    ssh -CNq -D "$PROXYPORT" "$USERNAME@$SSHHOST" -p $SSHPORT -o ServerAliveInterval=30 &
    echo "done."
}

stop ()
{  
    echo -n "Stopping tunnel.."
    PID=$(netstat -nlp -4 | grep ":$PROXYPORT")
    PID=$(echo $PID | sed "s/.*LISTEN\s*\(.*\)/\1/" | cut -f1 -d/)
    kill -9 $PID
    echo "done."
}

case "$1" in
  start|restart)
    start
    ;;
  stop)
    stop
    ;;
  restart)
    stop
    start
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|clear}"
    exit 1
    ;;
esac
exit 0
-----------------end of file------------------
---------/etc/default/sshtunnel----------
PROXYPORT=7777
USERNAME=abc
SSHHOST=abc
SSHPORT=22
-----------------end of file------------------
    首先准备一个远程服务器,获得域名端口,用户名密码。而后将上述脚本放置于指定位置,修改/etc/default/sshtunnel的值,即完成配置。但是上述脚本并没有解决自动登录问题,因此,请生成一个没有密码的密钥,将公钥导入远程服务器。
    在完成配置后,可用update-rc.d sshtunnel start 90 2 .进行自动启动服务的安装,其中的2请替换成服务器的默认启动级别。如果不知道可以用以下方法查询。
# cat inittab | grep ^id
id:2:initdefault: