关于 SOCKS 代理的远端 DNS 解析

经常使用 SOCKS 代理服务器的同志们会发现一种现象,即使 SOCKS 代理服务器设置正确,某些网站仍然无法访问,比如某著名微博网站。其一般原因都是 DNS 污染 (DNS cache poisoning)。

值得庆幸的是 SOCKS 5 可以通过将域名直接提交给 SOCKS 服务器来进行远端 DNS 解析,即 Address Type 0x03。DNS 服务是 Internet 的基础服务,要求 DNS 解析应当尽量地快,所以浏览器默认不会使用远端 DNS 解析。不过当使用自动代理设置脚本(.pac )时,以 SOCKS5 而不是 SOCKS 返回代理地址,可以支持远端 DNS 解析。

网友 forkei 的重要评论

chrome 的 Proxy Switchy 1.4.2 版本插件可以很好的解决这个问题。Firefox 的 FoxyProxy 插件也可以很好的解决 DNS 污染。支持插件扩展功能的浏览器功能就是强大。IE 内核浏览器和 opera 只有通过 polipo 或者 privoxy 将 socks 代理转为 http 代理才行,麻烦。

Tohr - HTTP 层上的洋葱路由器

Tohr (The Onion HTTP Router) 是我上个星期写的一个小的研究项目,它的名字起源于 Tor (The Onion Router)。简单地来说,它就是试图在 HTTP 层上实现类似于 Tor 实现的功能—— HTTP 层上的 HTTP(S) 隧道。

这个 idea 不是我想出来的,而是受到 GAppProxy 的启发(GAppProxy 是一个 great work)。但是 GAppProxy 只是利用 Google 的平台,而且受到 GAE 的很多限制。那么我的贡献呢,就是把这个 idea 通用化,设计一个协议使其支持多平台,解决了 GAppProxy 的一些 bug,完善了 HTTPS 的支持。(哦,忘记了,我还给它起了一个很 fancy 的名字 ^_^)目前 Tohr 的路由器可以是 Google App Engine 上的 Python 网站,也可以是普通的 Apache+PHP 站点。

Tohr 是怎么工作的?

Tohr 的工作原理

Tohr 的工作原理见上图。首先您得拥有一个墙外的主机(免费或者收费的)作为 Tohr 路由器,Tohr目前支持 Google App Engine 和 Apache+PHP 服务器,您将对应的 tohr-router 文件上传到服务器上;然后您在本地运行一个 tohr-daemon 守护程序,设置 tohr-daemon 连接 tohr-router 的 url,tohr-daemon 默认会开启 9090 来提供一个 HTTP(S) 代理服务,您只需要将浏览器的 HTTP 代理设置为 localhost:9090,您的访问请求就会通过 tohr-daemon 转发到 Tohr 路由器上,这样就能通过它来访问被防火墙禁止访问的网站了。

Tohr 是给什么人用的?

目前来讲 Tohr 仍然不很完善,而且还需要加入对其它类型的主机,比如 asp.net、jsp 的支持,还有对多跳和匿名的支持,还没有一个针对普通用户易用性的优化。要求普通用户都有一个墙外主机也是件比较为难的事情(虽然申请一个国外免费 PHP 空间并不困难,比如这里),因此 Tohr 目前还仅适合爱折腾的人使用,尤其是懂 Python 或 PHP 的爱折腾的人,所以在这里是找不到一个一步步的图文教程教普通用户怎么配置的。当然,如果哪位用户愿意做一个,请发送到邮件列表或者提交补丁,我很乐意将它放在项目文档里。

浏览器自动选择 Proxy 配置案例

本文主要讨论的是浏览器代理服务器设置技术,文中出现的人名、公司名或者域名均为化名,如有雷同,纯属巧合。

在某些地方上网时,比如南京大学的校园网中,某些公司的局域网中,我们可能需要用到代理服务器。代理服务器的切换一直是一个让人头痛的话题,IE 浏览器有一个 ProxySwither Lite 软件可以用来切换代理,Firefox 有一批插件可以用来切换代理,但是,很难用它们来解决全局性的问题,使用前的配置也是比较麻烦的事情。那么,有没有一种方法可以一劳永逸地解决这个问题呢?答案是有的,那就是 PAC(Proxy Auto-Config) 文件。

使用 PAC 文件我们可以做到:1. IE、Firefox、Opera...浏览器使用同一个代理配置方案,Windows、Linux多系统使用同一个代理配置方案;2. 针对特定的域名,使用特定的代理;3. 针对特定的 IP 范围,使用特定的代理;4. 针对特定的 URL 模式,使用特定的代理。

下面我们来看一个案例:

假设小明的电脑位于 C 公司的局域网中,C 公司为了某些需要禁止员工访问某些站点,例如: alogspot.com 和 bwitter.com ,但是小明的工作和学习需要经常访问这些站点,公司的网管给小明带来了很大不便。不过小明很聪明,他找到了一个可以访问被禁那些站点的一个代理 127.0.0.1:8000。虽然通过该代理小明可以访问这些站点,但是切换代理和浏览器设置始终是麻烦;特别是在用 doogle.com 搜索到的某些文章位于 alogspot.com 时,一不小心点了搜索结果,到搜索引擎 doogle.com 的连接就会有很大一会儿被重置。因为小明的代理速度比较慢,总不能用代理上所有网站吧?这真是件麻烦事,小明该怎么办呢?

虽然很头痛,但是互联网的开拓者们给我们留下了那么多遗产,怎么能不好好利用呢?小明翻出了一个尘封已久的 Wiki 页面,缓缓回忆起那古老的 Javascript 语言,顿时有了主意,于是他写出了下面这个 PAC 脚本:

// 看看域名是不是本地站点
function isLocalHost(host)
{
  if( dnsDomainIs(host, "localhost") )
    return true;
  return false;
}
// 看看域名是不是禁止访问的站点
function isBlockedHost(host)
{
  if( dnsDomainIs(host, "alogspot.com") ||
      dnsDomainIs(host, "bwitter.com") )
    return true;
  return false;
}
// 看看搜索结果 URL 中是不是包含被禁止访问的关键字
function isBlockedURL(url, host)
{
  if( dnsDomainIs(host, "doogle.com") ) {
    if ( shExpMatch(url, "*alogspot.com*") ||
         shExpMatch(url, "*bwitter.com*") )
      return true;
  }
  return false;
}
// 看看 IP 在不在本地 IP 范围内
function isLocalIP(addr)
{
  if( isInNet(addr,"127.0.0.0","255.0.0.0") ||
      isInNet(addr,"10.0.0.0","255.0.0.0") ||
      isInNet(addr,"192.168.0.0","255.255.0.0") ||
      isInNet(addr,"172.16.0.0","255.255.0.0") )
    return true;
  return false;
}
// 看看 IP 在不在被禁止访问的 IP 范围内
function isBlockedIP(addr)
{
  return false;
}
// 看看 IP 地址是不是 IPv6 地址
function isIPV6(addr)
{
  if( shExpMatch(addr, "*:*") )
    return true;
  return false;
}
// 这是浏览器默认调用的函数接口
function FindProxyForURL(url, host)
{
  var direct      = "DIRECT";
  var httpProxy   = "PROXY localhost:8000";
  var socksProxy  = "SOCKS localhost:9050"// 留着做个参考
 
  if(isLocalHost(host)) {
    // 如果是本地域名,那就直连
    return direct;
  } else if(isBlockedURL(url, host) || isBlockedHost(host)) {
    // 如果是被禁止访问的域名,或者搜索结果 URL 中含有被禁止访问的关键词,那就走代理
    return httpProxy;
  }

  if(!isResolvable(host)) {
    // 如果域名不能解析,那就直连
    return direct;
  }
  // 解析域名到 IP 地址
  var IpAddr = dnsResolve(host);

  if(isLocalIP(IpAddr) || isIPV6(IpAddr)) {
    // 如果是本地 IP 或者 IPv6 地址,那就直连
    return direct;
  } else if(isBlockedIP(IpAddr)) {
    // 如果是被禁止访问的地址,那就走代理
    return httpProxy;
  } else {
    // 剩下的,唉,就直连吧
    return direct;
  }
}

小明将以上内容保存为 C:proxy.pac(~/proxy.pac),然后到

Firefox 中,选择 工具->选项->高级->网络->设置(Edit->Preferences->Advanced->Network->Settings),将 file:///c:/proxy.pac(file:///home/username/proxy.pac)填入“自动代理配置 URL”(Automatic proxy configuration URL)文本框中;

再到

IE 中,选择 工具->Internet 选项->连接->局域网设置,勾选使用自动配置脚本,填入 file://c:/proxy.pac;

再到

Opera 中,选择 Tools->Preferences->Advanced->Network->Proxy Servers,勾选上 Use automatic proxy configuration,填入 file://c:/proxy.pac。

从此,小明就开始了自己幸福的互联网冲浪生活,再也没有看到那曾经熟悉的“到该网站的连接已被重置”消息了。

PS:若要 Firefox 和 Chrome 支持远端 DNS 解析,需使用 SOCKS5 作为代理的前缀。

解决 GAppProxy Set-Cookie 和 HTTPS Cert Bugs

我自己写了一个类似 GAppProxy 的工具,支持 Python 和 PHP,有兴趣可以看这里

研究 GAppProxy 有两个原因:一、最近 Twitter 不能用,而我常用的 GAppProxy 却不支持我登录 Twitter;二、我最近在琢磨 SSL 证书的问题,正好用 GAppProxy 登录 Twitter 也有证书错误。

第一个 BUG:Set-Cookie Bug

GAPPProxy 目前对 Cookie 的处理有一些问题,主要出在对 header 中的多个 Set-Cookie 域处理错误,就会导致用户登录一些网站错误,无法获得正确的会话 Cookie。

举例,当服务器返回的 header 中有多个 Set-Cookie 域时,比如一般的 wordpress 返回的 header 中,Set-Cookie 域至少有三个:

Set-Cookie:
wordpress_776c41a2fee8d137928f3750eb1f0736=admin%7C1247298611%7C8b89cfc80161853957182ddfc481cd72;
path=/wp-content/plugins; httponly
Set-Cookie:
wordpress_776c41a2fee8d137928f3750eb1f0736=admin%7C1247298611%7C8b89cfc80161853957182ddfc481cd72;
path=/wp-admin; httponly
Set-Cookie:
wordpress_logged_in_776c41a2fee8d137928f3750eb1f0736=admin%7C1247298611%7C545dcea44d5e69aec5c1203c64bee061;
path=/; httponly

GAPPProxy 会把它作为一个串传给本地浏览器:

Set-Cookie:
wordpress_776c41a2fee8d137928f3750eb1f0736=admin%7C1247298611%7C8b89cfc80161853957182ddfc481cd72;
path=/wp-content/plugins; httponly,
wordpress_776c41a2fee8d137928f3750eb1f0736=admin%7C1247298611%7C8b89cfc80161853957182ddfc481cd72;
path=/wp-admin; httponly,
wordpress_logged_in_776c41a2fee8d137928f3750eb1f0736=admin%7C1247298611%7C545dcea44d5e69aec5c1203c64bee061;
path=/; httponly

这样本地浏览器对 Cookie 的设置就会错误。解决办法很简单,将这个长串用split(', ')切开,同样设置三个 Set-Cookie 域即可。

Update 20090710/Solrex:
有人评论说 ', ' 也是可能在 Cookie 中出现的合法字符串;那么我就另外想了一个办法,先用正则表达式替换将 ', ***=' 替换成 'n***=',再用 'n' 对字符串进行切割。由于在 Cookie 中正常出现的 ', ' 后面会首先跟着 ';' 或 ',',然后才可能出现 =,因此用 ‘, ([^,;]+=)’ 匹配就可以了。而且这次把修改放到服务器端了,原来的客户端就不需要修改了

Patch:

Index: fetchserver/fetch.py
===================================================================
--- fetchserver/fetch.py    (revision 92)
+++ fetchserver/fetch.py    (working copy)
@@ -29,6 +29,7 @@
from google.appengine.ext import webapp
from google.appengine.api import urlfetch
from google.appengine.api import urlfetch_errors
+import re
# from accesslog import logAccess

@@ -153,14 +154,12 @@
             if header.strip().lower() in self.HtohHdrs:
                 # don't forward
                 continue
-            ## there may have some problems on multi-cookie process in urlfetch.
-            #if header.lower() == 'set-cookie':
-            #    logging.info('O %s: %s' % (header, resp.headers[header]))
-            #    scs = resp.headers[header].split(',')
-            #    for sc in scs:
-            #        logging.info('N %s: %s' % (header, sc.strip()))
-            #        self.response.out.write('%s: %srn' % (header, sc.strip()))
-            #    continue
+            # NOTE 20090710/Solrex: Fix multi-cookie process problem
+            if header.lower() == 'set-cookie':
+                scs = re.sub(r', ([^,;]+=)', r'n1', resp.headers[header]).split('n')
+                for sc in scs:
+                    self.response.out.write('%s: %srn' % (header, sc.strip()))
+                continue
             # other
             self.response.out.write('%s: %srn' % (header, resp.headers[header]))
             # check Content-Type

第二个 BUG:HTTPS Cert Bug

简单地来说,GAppProxy HTTPS 连接的实现是一个欺骗本地浏览器的过程,类似于中间人攻击。它首先用 GAE 获得页面的明文,抓到本地,然后假冒 HTTPS 站点与本地浏览器通信。因此它就需要提供一个 SSL 证书,来完成 HTTPS 连接的建立。

但这就有一个问题,SSL 证书哪儿来的?目前 GAppProxy 对所有的站点都使用一个证书,而且这个证书是未经任何授权 CA 认证的证书,因此就会产生很多错误。首先,该证书中的授权机构不是可信 CA,Firefox 和 IE 中捆绑的证书中没有该 CA 的证书;其次,该证书的 CN (Common Name)与站点域名不同,不可用于站点的通信。因此可能每次都需要用户自己点击添加证书例外。

为了避免这种缺陷,我想出来的做法是——自己做 CA,正所谓做事情要专业,要骗就骗彻底点,骗得浏览器神不知鬼不觉。首先,建立 CA 的密钥,自己给自己签发一个证书作为 CA 的根证书,将该 CA 的证书安装到 Firefox 浏览器中,在运行时使用该 CA 为每个 HTTPS 连接的站点签发对应于该站点的证书。由于 Firefox 中已经安装了该 CA 的证书,那么所有该 CA 签发的证书都能够通过 Firefox 的检测了。

这个方法比较麻烦,而且需要电脑上有 openssl,对于 Linux 完全没有问题,对于 Windows 可能就有点儿困难了。所以我这里就给出个思路,具体实现就不谈了。
您可以在 http://share.solrex.org/ibuild/ 找到我修改后的代码,感兴趣的话可以下载下来看看。

内网穿透反向隧道代理技术

本文的主要目的是利用使 ssh 服务器(外网)通过客户端(内网)代理上网以及反向控制客户端(内网),不需要网络管理员权限,不需要 NAT。即可上网主机 A 位于内网,不可上网主机 B 位于外网,A 能直接访问 B,但 B 无法访问防火墙内的 A,这样 B 就可以使用 SSH 隧道访问 A 主机上的代理服务器上网。(估计有这种变态需求的人只存在于大学中)

B(210.77.*.*)---->(210.77.*.*)FW(192.168.0.*)|--->(192.168.0.*)A---->(192.168.0.*)FW(123.*.*.*)---->Internet
B(210.77.*.*)< ----(210.77.*.*)FW(192.168.0.*)-----(192.168.0.*)A<----(192.168.0.*)FW(123.*.*.*)<----Internet

一、代理

首先在客户端上安装 socks 代理(HTTP 代理可以使用 Squid,同理)。socks 代理软件使用 Dante。Dante 的启动以及配置需要手动调整,下面是 Dante 的配置文件 /etc/sockd.conf:

compatibility:reuseaddr
internal:0.0.0.0 port = 1080
external:eth0
logoutput:/var/log/sockd/sockd
clientmethod:none
method:none
user.privileged:root
user.notprivileged:solrex
connecttimeout:60
iotimeout:86400

## client access rules
client pass {
 from: 127.0.0.1/0 port 1-65535 to: 0.0.0.0/0
 log: connect disconnect
}

## server operation access rules
#allow bind to ports greater than 1023
pass {
  from: 0.0.0.0/0 to: 0.0.0.0/0 port gt 1023
  command: bind bindreply udpassociate udpreply
  log: connect disconnect
}

pass {
  from: 0.0.0.0/0 to: 0.0.0.0/0 port 1-65535
  protocol: tcp udp
  log: connect disconnect
}

#allow outgoing connections (tcp and udp)
pass {
  from: 127.0.0.1/0 to: 0.0.0.0/0
  command: bind bindreply connect udpassociate udpreply
  log: connect disconnect
}

#allow replies to bind, and incoming udp packets
pass {
   from: 0.0.0.0/0 to: 0.0.0.0/0
   command: bind bindreply connect udpassociate udpreply
   log: connect error
}

#log the rest
block {
   from: 0.0.0.0/0 to: 0.0.0.0/0
   log: connect error
}

下面是 Dante 的启动脚本 /etc/init.d/sockd:

#!/bin/sh
set -e

. /lib/lsb/init-functions

[ -f /usr/local/sbin/sockd ] || exit 0

[ ! -f /etc/sockd.conf ] && exit 1
SOCKD_CONF="-f /etc/sockd.conf"

SOCKD_OPTS="-D"

case "$1" in
  start)
    # Start daemons.
    log_daemon_msg "Starting Dante socks proxy server" "sockd"
    if start-stop-daemon --start --quiet --oknodo --pidfile /var/run/sockd.pid --exec /usr/local/sbin/sockd -- $SOCKD_OPTS; then
	    log_end_msg 0
	else
	    log_end_msg 1
	fi
    ;;
  stop)
    # Stop daemons.
    log_daemon_msg "Stoping Dante socks proxy server" "sockd"
	if start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/sockd.pid; then
	    log_end_msg 0
	else
	    log_end_msg 1
	fi
	;;
  restart)
    log_daemon_msg "Restarting Dante socks proxy server" "sockd"
	start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile /var/run/sockd.pid
	if start-stop-daemon --start --quiet --oknodo --pidfile /var/run/sockd.pid --exec /usr/local/sbin/sockd -- $SOCKD_OPTS; then
	    log_end_msg 0
	else
	    log_end_msg 1
	fi
	;;
  *)
    log_action_msg "Usage: /etc/init.d/sockd {start|stop|restart}\n"
    exit 1
esac

exit 0

二、ssh 服务器

服务器端 ssh 服务器最好采用 Openssh,Windows 下应该使用 Cygwin 运行 sshd,FreeSSHd 实践证明崩溃比较频繁。同一台机器的 Windows 和 Linux 上运行的 ssh 服务器最好使用相同的 host key,将 /etc/ssh/ 下面的文件保持一致即可。最好配置服务器为使用公钥进行登录验证,这样能使用自动脚本进行端口映射。

三、手动建立隧道(客户端到服务器端口映射)

用下面命令建立客户端到服务器的端口映射,将客户端的 socks 代理端口 1080 映射到服务器的端口 8080。这样服务器就可以通过自己的 8080 端口反向隧道到客户端的 socks 代理 1080 端口上网。

ssh -C -f -N -g -o PreferredAuthentications=publickey -R SERVER:8080:127.0.0.1:1080 USRNAME@SERVER
# 参数含义:
# -C: 要求对数据进行压缩
# -f:要求 ssh 执行完交互后进入后台运行
# -N:不用建立一个终端
# -g:允许远程服务器连接客户端转发端口
# -R SERVER:8080:127.0.0.1:1080:将客户机(127.0.0.1)的 1080 端口绑定到服务器(SERVER)的 8080 端口。
# USRNAME@SERVER:ssh服务器的用户名和密码
# -p 3022:ssh服务器的端口

为了方便控制,最好也将客户端的 ssh 服务器端口映射到服务器端,服务器端就可以通过登录自己的 8022 端口来登录客户端的 ssh 服务器:

ssh -C -f -N -g -o PreferredAuthentications=publickey -R SERVER:8022:127.0.0.1:22 USRNAME@SERVER

这样两台被防火墙隔开的主机就能实现双向控制。

四、自动建立隧道

手动建立隧道的缺陷是服务器端必须长期开机,并且连接只能用户在客户端手动发起。可以考虑间接的办法,比如使用两台主机均可访问的服务器作为跳板,或者客户端自动登录聊天软件,利用聊天软件接受指令。下面给出一种使用共享服务器的方法:

#!/bin/bash
# {start|stop|restart:username:ipaddress}

COMMAND="stop"
SERVER="0.0.0.0"
USRNAME=""
PORT="22"

INFOURL="http://someserver.com/somepage"

SSHOPTS="-C -f -N -g -o PreferredAuthentications=publickey -o StrictHostKeyChecking=no"

get_server_info()
{
  #info=`wget -nv -O - $INFOURL 2> /dev/null | iconv -f gbk -t utf8 |
        grep -o -e "{.*}" | tr -d '{}'`
  info=`wget -nv -O - $INFOURL 2> /dev/null | iconv -f gbk -t utf8 |
        sed -n "/{*}/s/.*{\(.*\)}.*/\1/p"`
  COMMAND=${info%%:*}
  SERVER=${info#*:}
  USRNAME=${SERVER%:*}
  SERVER=${SERVER#*:}
}

tunneling_status()
{
  tun_ps=`ps aux | grep "ssh -C" | wc -l`
  if [ $tun_ps -gt 4 ]; then
    echo -n "running"
  else
    echo -n "died"
  fi
}

start_tunneling()
{
  ssh $SSHOPTS -R 3128:127.0.0.1:3128 ${USRNAME}@${SERVER} -p $PORT
  ssh $SSHOPTS -R 8022:127.0.0.1:22 ${USRNAME}@${SERVER} -p $PORT
}

failsafe_tunneling()
{
  ssh $SSHOPTS -R 8022:127.0.0.1:22 ${USRNAME}@${SERVER} -p $PORT
}

stop_tunneling()
{
  killall -e ssh
}

echo -n "[`date +%F\ %R`] "
get_server_info

case "$COMMAND" in
  start)
    if [ $(tunneling_status) = "running" ]; then
      echo "Starting ssh tunneling.(started, do nothing)"
    else
      echo "Starting ssh tunneling."
      start_tunneling
    fi
    ;;
  restart)
    if [ $(tunneling_status) = "running" ]; then
      echo "Restarting ssh tunneling."
      stop_tunneling
      start_tunneling
    else
      echo "Restarting ssh tunneling."
      start_tunneling
    fi
    ;;
  stop)
    if [ $(tunneling_status) = "running" ]; then
      echo "Stoping ssh tunneling."
      stop_tunneling
    else
      echo "Stoping ssh tunneling.(stoped, do nothing)"
    fi
    ;;
  failsafe)
    echo "Starging ssh tunneling.(failsafe mode)"
    failsafe_tunneling
    ;;
  sleep)
    echo "Sleeping."
    exit 0
    ;;
  *)
    echo "Unrecogenized server command ($COMMAND)."
    exit 1
    ;;
esac

exit 0

将上面脚本加入 crontab 每十分钟运行一次,就能实现在服务器端对客户端进行有限的控制。

Tor - Anonymity on Line

其实以前就见过 Baosheng 在博客里推荐 Tor 这个工具,据说可以访问 Wikipedia,只是当时潜意识里觉得太麻烦,就懒得搞。昨天晚上 Baosheng bg,请 ufx222, xum84, daoming, proline 我们一起吃饭,又提到了这个洋葱路由,今天就尝试了一下,果然好用。

简单来说,Tor 的功能就是,采用不同的“洋葱路由器(onion router 意思和代理服务器差不多)”来重定向网络请求,并且随时间更换路由,这样别人就无法监视你的网络访问情况,主要目的是为了保护隐私。而由此带来的副产品就是,onion routers 遍布全世界各地,所以就可以使用这个工具通过 onion routers 访问被“墙”封掉的站点(比如现在的 blogspot.com )。更多介绍请登录 Tor 官方网站 [href: http://tor.eff.org/ ] 。

从我的使用来看,刚开始使用访问网站速度可能慢点儿,用了一段时间之后速度就快很多了,大概是 Tor 自动在寻找洋葱路由服务器。而且最牛的是,我们公司的 DNS 坏了一小段时间,其间什么网站都没办法访问,而通过 Tor 居然访问正常,大概是 Tor 记录的是 IP 而不是 domain 吧。有意思的是访问 google.com 往往被重定向到某个欧洲的 Google 服务器,比如: google.de, google.es 之类的。

在 Linux 下 Tor 的配置很简单(我估计在 Windows 下会更简单,官方网站上有各种系统安装介绍):

首先,安装 Tor 软件,在 Ubuntu 下面就是:
sudo apt-get install tor
使用默认配置即可,即在 9050 端口打开一个 SOCKS 服务器。Tor 程序会以后台方式一直运行在系统里。

其次,为 Firefox 下载 torbutton 插件[href: https://addons.mozilla.org/en-US/firefox/addon/2275 ],安装。安装完成后,到"Tools->Add-ons->Extensions->Torbutton Preferences",在 "Proxy Settings" 中选择 "Use custom proxy settings",然后将前四个都留空,最后 "SOCKS Host:" 中填: localhost, Port: 9050,这样配置就完成了。

可以留意 Firefox 状态栏的最右端(窗口右下角),这时候会出来一个 "Tor Disabled",用鼠标点击该区域,就可以在 "Tor Disabled/Tor Enabled" 状态切换。这样在访问某些敏感站点时候就可以 Enable 它,在不需要时 Disable 它。也可以在 Torbutton Preferences中把这个文字格式的提醒改成一个洋葱头的图标提醒。

其实我想,不安装插件,只在网络设置中使用 SOCKS 代理也可以实现这种功能,如果这样的话,这里插件的作用只是启用和不启用代理的区别。那么,如果在校园网内,这个插件能否起到在 Firefox 的代理和插件这两个代理之间切换的目的呢?如果可以的话,就算不使用或者不能使用 Tor,这个插件也可以用作切换校园网代理使用了,倒也蛮方便的(只是我不需要用到了,所以就留给别人验证吧 X-D)。

PS: Yo2.cn 服务质量在下降,从 2007年7月19日8:25 到 9:00 之间都无法连接上,wget 可以下载但无法显示速度,更无法登录,最后出来一个错误:504 Gateway Time-out。唉,国产的 BSP 千万别学国产的足球队啊!烦死了,回去睡觉。