使用 openvpn 并配合 chnroutes 脚本上网已经很完美了,在访问国外的 ip 时自动使用 vpn 线路,在访问国内的 ip 时则自动选用非 vpn 线路,为什么还要使用 dnsmasq 呢?原因如下:

由于有域名污染,所以 dns 只能使用 8.8.8.8 或者 opendns 之类的进行解析;而使用国外的 dns 之后,在解析某些使用了智能 dns 的服务时,智能 dns 服务器往往会选择错 ip 地址,就会导致:

  1. 明明是国内的服务,却解析到一个国外的 ip,并使用 vpn 进行访问,导致速度慢
  2. 自己的电信的线路,却解析到网通的 ip,访问同样也会受到影响

为了解决上述问题,就需要将这些域名转发到自己所在的 isp 提供的 dns 进行解析。一般的 dns 服务器软件都提供这样的功能,不过这里用不到那么复杂的功能。而之前介绍 dns 缓存的时候使用到的 dnsmasq 也能提供转发功能,因此这里就继续使用 dnsmasq。配置极其简单,只需要在配置文件 /etc/dnsmasq.conf 中对 server 字段进行配置即可,比如我的配置:

no-resolv
no-poll
server=8.8.8.8
server=8.8.4.4
server=/qq.com/192.168.1.1

表示默认使用 8.8.8.8 和 8.8.4.4 解析,当解析 *.qq.com 的时候使用 192.168.1.1 解析。你需要把 192.168.1.1 换成你 isp 提供的 dns 服务器。
最后,启动 dnsmasq 服务,把自己的 dns 服务器指向 127.0.0.1 即可,由于我使用了 resolvconf,所以直接在 /etc/resolvconf.conf 中加入一下配置即可:

name_servers=127.0.0.1

下面可以使用 dig 命令进行一个简单的测试:

$ dig @8.8.8.8 web2.qq.com
 
; <<>> DiG 9.8.0 <<>> @8.8.8.8 web2.qq.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6525
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
 
;; QUESTION SECTION:
;web2.qq.com.			IN	A
 
;; ANSWER SECTION:
web2.qq.com.		221	IN	A	112.90.138.163
web2.qq.com.		221	IN	A	112.90.138.164
web2.qq.com.		221	IN	A	112.90.141.88
 
;; Query time: 217 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Wed Jul 20 00:17:59 2011
;; MSG SIZE  rcvd: 77
$ dig @192.168.1.1 web2.qq.com
 
; <<>> DiG 9.8.0 <<>> @192.168.1.1 web2.qq.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13332
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0
 
;; QUESTION SECTION:
;web2.qq.com.			IN	A
 
;; ANSWER SECTION:
web2.qq.com.		101	IN	A	183.62.126.217
web2.qq.com.		101	IN	A	183.60.3.126
web2.qq.com.		101	IN	A	121.14.74.112
web2.qq.com.		101	IN	A	183.60.3.84
 
;; Query time: 10 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Wed Jul 20 00:18:06 2011
;; MSG SIZE  rcvd: 93
$ dig @127.0.0.1 web2.qq.com
 
; <<>> DiG 9.8.0 <<>> @127.0.0.1 web2.qq.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23246
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0
 
;; QUESTION SECTION:
;web2.qq.com.			IN	A
 
;; ANSWER SECTION:
web2.qq.com.		94	IN	A	183.60.3.84
web2.qq.com.		94	IN	A	121.14.74.112
web2.qq.com.		94	IN	A	183.60.3.126
web2.qq.com.		94	IN	A	183.62.126.217
 
;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Jul 20 00:18:13 2011
;; MSG SIZE  rcvd: 93
$ dig @127.0.0.1 twitter.com
 
; <<>> DiG 9.8.0 <<>> @127.0.0.1 twitter.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57641
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
 
;; QUESTION SECTION:
;twitter.com.			IN	A
 
;; ANSWER SECTION:
twitter.com.		19	IN	A	199.59.149.198
twitter.com.		19	IN	A	199.59.149.230
twitter.com.		19	IN	A	199.59.148.10
 
;; Query time: 205 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Jul 20 00:26:57 2011
;; MSG SIZE  rcvd: 77

可以看到使用 8.8.8.8 时解析到了网通的地址,而使用 127.0.0.1 后,则可以正确的解析为电信的地址。同时解析 twitter.com 也能正确的返回结果。


本文讲述我的 xmonad 桌面的配置,它使用 xmobar 显示各种状态,使用 taryer 来提供 systray。

xmonad 是一种平铺式窗口管理器,窗口之间不会遮挡,且自动调整大小以填充整个屏幕,这样就节省了使用鼠标调整各个窗口位置的时间,一切的操作都可以通过自定义的快捷键来完成。

xmonad 是由 Haskell 开发的,其配置文件也是使用 Haskell 来配置的,不过了解一些简单的语法之后,配置起来也是很方便的。当然默认的配置就已经非常好用了,我也只是在默认的配置上进行了一点小的修改而已。
下面是我的 xmonad 配置与默认配置之间的差异(只是为了表现差异,最后会有整个配置文件的下载):

--- /usr/share/xmonad-0.9.2/ghc-7.0.4/man/xmonad.hs 2011-07-05 00:22:51.800397623 +0800
+++ .xmonad/xmonad.hs 2011-07-14 22:39:43.118625125 +0800
@@ -14,10 +14,15 @@
import qualified XMonad.StackSet as W
import qualified Data.Map as M

+import XMonad.Util.Run
+import XMonad.Hooks.DynamicLog
+import XMonad.Hooks.ManageHelpers
+import XMonad.Util.Cursor
+
-- The preferred terminal program, which is used in a binding below and by
-- certain contrib modules.
--
-myTerminal = "xterm"
+myTerminal = "gnome-terminal"

-- Whether focus follows the mouse pointer.
myFocusFollowsMouse :: Bool
@@ -32,7 +37,7 @@
-- ("right alt"), which does not conflict with emacs keybindings. The
-- "windows key" is usually mod4Mask.
--
-myModMask = mod1Mask
+myModMask = mod4Mask

-- The mask for the numlock key. Numlock status is "masked" from the
-- current modifier status, so the keybindings will work with numlock on or
@@ -127,6 +132,12 @@
-- Deincrement the number of windows in the master area
, ((modm , xK_period), sendMessage (IncMasterN (-1)))

+ -- screenshot screen
+ , ((modm , xK_Print), spawn "/usr/bin/screenshot scr")
+
+ -- screenshot window or area
+ , ((modm .|. shiftMask, xK_Print), spawn "/usr/bin/screenshot win")
+
-- Toggle the status bar gap
-- Use this binding with avoidStruts from Hooks.ManageDocks.
-- See also the statusBar function from Hooks.DynamicLog.
@@ -221,6 +232,7 @@
myManageHook = composeAll
[ className =? "MPlayer" --> doFloat
, className =? "Gimp" --> doFloat
+ , isFullscreen --> doFloat
, resource =? "desktop_window" --> doIgnore
, resource =? "kdesktop" --> doIgnore ]

@@ -239,9 +251,13 @@
-- Status bars and logging

-- Perform an arbitrary action on each internal state change or X event.
--- See the 'XMonad.Hooks.DynamicLog' extension for examples.
+-- See the 'DynamicLog' extension for examples.
+--
+-- To emulate dwm's status bar
+--
+-- > logHook = dynamicLogDzen
--
-myLogHook = return ()
+myLogHook = dynamicLog

------------------------------------------------------------------------
-- Startup hook
@@ -251,14 +267,19 @@
-- per-workspace layout choices.
--
-- By default, do nothing.
-myStartupHook = return ()
+myStartupHook = do
+ spawn "fcitx"
+ setDefaultCursor xC_left_ptr
+ spawn "feh --bg-scale /home/zhanglei/Pictures/mlxmonadwall1trans.png"
+ spawn "trayer --edge top --align right --widthtype percent --width 10 --SetDockType true --SetPartialStrut true --transparent true --alpha 0 --tint 0x000000 --expand true --heighttype pixel --height 25"
+ --return ()

------------------------------------------------------------------------
-- Now run xmonad with all the defaults we set up.

-- Run xmonad with the settings you specify. No need to modify this.
--
-main = xmonad defaults
+main = xmonad =<< xmobar defaults

-- A structure containing your configuration settings, overriding
-- fields in the default config. Any you don't override, will

以上修改的一些简单说明:

  • 使用 gnome-terminal 作为我的终端
  • 使用 Win 健作为 xmonad 的 Mod 健,默认为 Alt,但是会和 bash 的一些快捷键冲突
  • 增加了两个快捷键 Win + Print 与 Win + Shift + Print 用来进行截图
  • 加入 isFullscreen –> doFloat 以解决 flash 不能全屏的问题
  • myLogHook = dynamicLog 可以让 xmobar 显示出当前的状态
  • 在 myStartupHook 函数中加入我的启动项:
    1. fcitx 输入法
    2. 设置鼠标样式
    3. 使用 feh 设置桌面背景
    4. 启动 trayer 以显示 systary
  • 最后,main 函数中使用 xmobar 函数启动 xmobar

下面是一些经常使用到的快捷键:

  • Win + Shift + Enter: 启动 Terminal
  • Win + P: 启动 dmenu,用于启动各种命令
  • Win + 1 – 9: 在 1 – 9 虚拟桌面中进行切换
  • Win + Shift + 1 – 9: 将当前的窗口移动到指定的虚拟桌面
  • Win + Tab: 在同一虚拟桌面中的窗口之间切换
  • Win + Shift + C: 杀死当前窗口
  • Win + Q: 重启 xmonad,用于改为配置之后使其生效

下面是我的 xmobar 的配置,其配置文件为 .xmobarrc

Config { font = "xft:WenQuanYi Zen Hei Mono-12"
, bgColor = "black"
, fgColor = "grey"
, position = TopW L 90
, lowerOnStart = True
, commands = [ Run Weather "ZGSZ" ["-t",": C","-L","18","-H","25","--normal","green","--high","red","--low","lightblue"] 36000
, Run Network "eth0" ["-L","0","-H","32","--normal","green","--high","red"] 10
, Run Network "eth1" ["-L","0","-H","32","--normal","green","--high","red"] 10
, Run Cpu ["-L","3","-H","50","--normal","green","--high","red"] 10
, Run Memory ["-t","Mem: %"] 10
, Run Swap [] 10
, Run StdinReader
, Run Com "uname" ["-s","-r"] "" 36000
, Run Date "%a %b %_d %Y %H:%M:%S" "date" 10
]
, sepChar = "%"
, alignSep = "}{"
, template = "%cpu% | %memory% * %swap% | %eth0% | %StdinReader% }{ <fc=#ee9a00>%date%</fc> | %ZGSZ% | %uname%"
}

其中有三点值得注意:

  1. position 指定了 xmobar 的位置:左上,长度 90%,而 trayer 的则为右上,长度 10%。刚好能够接上。
  2. 深圳天气的代码为 ZGSZ,其他地方的可以到这个页面进行查询。
  3. 需要有 StdinReader,否则在 xmonad 中的 dynamicLog 函数就不会起作用。

最后,提供这两个配置文件的下载:
xmonad.hs
.xmobarrc


本文讲述使用 vps 搭建 openvpn,以及在 Gentoo 中使用 chnroutes 修改路由表,将国内 ip 的访问重新指定为非 vpn 线路。

条件

服务器为支持 Tun/Tap 的 vps: 我自己的 Directspace 的 vps,默认是没有开启的,需发 Tk 开启。免费的 AWS EC2 是默认开启了的。我这里的 vps 安装的操作系统为 Debian。

客户端为 Linux:我用的为 Gentoo,其他发行版的脚本和启动 openvpn 的方式可能会不一样

在 vps 中安装与配置 openvpn 服务器

安装 openvpn 软件,很简单:

aptitude install openvpn

生产服务器证书:

cd /etc/openvpn/
cp /usr/share/doc/openvpn/examples/easy-rsa/2.0/* .
source ./vars
./clean-all
./build-ca
./build-key-server server
./build-dh
./build-key client1

在 ./build-key-server server 和 ./build-key client1 两步时会询问是否签名,回答是,如下,其他使用默认即可:

...
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y

好了,此时,在 /etc/openvpn/keys 目录下面就有了服务器和客户端所需的证书
下面修改服务器配置文件:/etc/openvpn/server.conf,我只提取有用部分:

port 53
proto udp     # 我这里采用 udp 的 53 端口通信,和 dns 解析用的端口一样 ...
dev tun
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/server.crt
key /etc/openvpn/keys/server.key
dh /etc/openvpn/keys/dh1024.pem    # 以上4个指定服务器证书的路径
server 10.8.0.0 255.255.255.0      # 配置ip地址段
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1 bypass-dhcp"    # 默认路由走 vpn,后面在客户端设置时会将国内的 ip 再修改回非 vpn 的路由
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"    # 使用 Google 的 DNS
client-to-client    # vpn 客户端之间可以通信
duplicate-cn        # 多个客户端可以使用同一个证书
keepalive 10 120
comp-lzo
user nobody
group nogroup
persist-key
persist-tun
status openvpn-status.log
log /var/log/openvpn.log
verb 3

一些注释都在上面了。然后启动 openvpn 服务器了

/etc/init.d/openvpn start

服务器上面还有最后两件事情:打开路由转发选项和配置 SNAT 规则
打开路由转发:修改 /etc/sysctl.conf 文件,将 net.ipv4.ip_forward=1 前面的注释去掉

...
net.ipv4.ip_forward=1
...

然后执行命令:

sysctl -p

最后设置 MASQUERADE 规则,将 10.8.0.0 网段过来的数据包转发出去后都将源地址修改为本机的 IP 地址,以使回复包能够正确的回到 vps 上。命令:

iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

其中 eth0 要改为 vps 上面的网络接口名称,比如在 Directspace 上面就为 venet0;
当然这样只是当前生效,vps 重启之后还得重新配置 MASQUERADE 规则,可以使用如下语句将当前的 iptables 规则保存起来,然后在开机的时候加载

iptables-save > /etc/openvpn/iptables

在 /etc/rc.loacl 中加入如下语句:

iptables-restore < /etc/openvpn/iptables

好了,服务器配置就完成了

在 Gentoo 下配置 openvpn 客户端

首先同样为安装 openvpn 软件,我这里是 Gentoo,你需要使用你用的发行版的包管理安装

emerge openvpn openresolv iproute2

安装 openresolv 是为了需要 resolvconf 程序,用于修改 dns 配置的,其他发行版可能不太一样
安装 iproute2 是为了获得 ip 程序,在修改路由时会使用到。
客户端需要使用在配置服务器端时生成的 key,需要如下三个文件:

ca.crt  client1.crt  client1.key

同样,我这里也放到了 /etc/openvpn/keys 目录
然后配置 /etc/openvpn/client.conf

client
dev tun
proto udp
remote xxx.xxx.xxx.xxx 53      # 这里需要换成你自己的服务器,域名或 IP
resolv-retry infinite
nobind
persist-key
persist-tun
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/client1.crt
key /etc/openvpn/keys/client1.key    # 你自己的证书路径
comp-lzo
verb 3
redirect-gateway
script-security 2

创建启动脚本

ln -vs openvpn /etc/init.d/openvpn.client

然后使用如下命令启动即可

/etc/init.d/openvpn.client start

但是,这样启动之后,所有的流量都回走 vpn,因此访问国内资源时很慢,且有可能会有限制,所以接下来就需要使用 chnroutes 的方法将访问国内 ip 的路由修改为非 vpn 的线路
下载 chnroutes.py 文件,然后执行

python chnroutes.py -p linux

之后,目录下面就会多出两个文件:

ip-pre-up ip-down

然后将这两个文件拷贝到 /etc/openvpn/ 目录并改名,同时加上可执行权限:

cp ip-pre-up /etc/openvpn/openvpn.client-up.sh
cp ip-down /etc/openvpn/openvpn.client-down.sh
chmod 755 /etc/openvpn/openvpn.client-up.sh
chmod 755 /etc/openvpn/openvpn.client-down.sh

Gentoo 下面会在 vpn 启动和停止的时候自动调用上面两个脚本。这时再运行

/etc/init.d/openvpn.client start

过不一会儿,使用 ip 命令查看路由表信息就可以看到国内的 ip 都走了非 vpn 的线路

$ ip r
0.0.0.0/1 via 10.8.0.9 dev tun0
default via 192.168.1.1 dev eth0  metric 2
1.0.1.0/24 via 192.168.1.1 dev eth0
1.0.2.0/23 via 192.168.1.1 dev eth0
1.0.8.0/21 via 192.168.1.1 dev eth0
1.0.32.0/19 via 192.168.1.1 dev eth0
1.1.0.0/24 via 192.168.1.1 dev eth0
1.1.2.0/23 via 192.168.1.1 dev eth0
1.1.4.0/22 via 192.168.1.1 dev eth0
1.1.8.0/21 via 192.168.1.1 dev eth0
...

好了,现在可以打开 Youtube 看下视频了,AWS EC2 的免费 vpn 速度可以到 400K,已经很不错了,不过流量每月只有 30G :)


最近在做http的压缩,稍微了解了下gzip,deflate,zlib的关系:

可以看出deflate是最核心的算法,而zlib和gzip格式的区别仅仅是头部和尾部不一样,而实际的内容都是deflate编码的,即:
gzip = gzip头 + deflate编码的实际内容 + gzip尾
zlib = zlib头 + deflate编码的实际内容 + zlib尾

在HTTP/1.1的RFC2616文档中说明了Content-Encoding字段的值可以为:gzip, deflate等。

gzip格式大家都支持的很好很标准,这里说下deflate格式,Content-Encoding的说明中指出deflate指的是在RFC1950说明的zlib格式。也就是说当Content-Encoding为deflate时,内容应该为zlib格式。

但是,实际上,如果真的按照这个标准来,那么在IE上面是打不开页面的,包括IE6,IE7,IE8,提示为一片空白或者出错。但是在其他的浏览器如Firefox,Chrome,Opera等上面都能正常打开。要让IE能够正常打开页面,内容必须是deflate原始格式的数据,即去掉zlib头和zlib尾。不知道IE为什么不修改这个Bug,按理说在IE6就出现的这种很简单的问题,IE8不应该出现才对。

为了照顾IE,只好在压缩deflate的时候去掉zlib头和zlib尾,还好其他的浏览器也都能正常处理这种原始的deflate格式。
当然,这样的话,那些受够了IE Only的人们倒是可以创建出一个IE不能正常访问的网站了。


现在再过半个小时就到10年了,利用这半个小时的时间对我的09年做个总结。

总的来说,09年是一个杯具年。

  • 奶奶去世,让我伤心了好久,我奶奶身体一向很好,过年的时候还经常种菜什么的,没想到说走就走
  • 手机的丢失,刚买了不到一年的钻石,在一次喝多了之后就再也找不到了
  • GFW越来越高,越来越多的网站需要翻墙,而翻墙也越来越有难度
  • 墙内越来越和谐,基本上是个新闻都是不让评论的,当然,人家说网上言论非常活跃,也许我错了

“中国以及和中国一起混的国家都是些流氓国家”,终于觉得我同事这句活说的太好了

当然09年也不是什么都不好

  • 换了房子,从离公司很远的地方搬到了离公司还是很远的地方…不过一个在关外,一个在关内,总算住在深圳市内了…
  • 买了自行车,除了每周踢球外,另一个锻炼身体的运动
  • 买了望远镜,每当心情不好的时候就看看美丽的宇宙,顿觉人类的渺小,于是什么不开心的事都坦然了
  • 买了个佳能500D,我承认目的只是想用来拍星空的,不过出去的时候带上拍拍其他的东西也不错
  • 买个域名和空间,开始了我的独立博客,都是买的国外的,国内的不放心

好了,已经到10年了,其他的也没什么好说的了,都是老样子。