如果你只是需要一個能在熄燈之後使用的路由器,請在網上買一個帶電池的路由器,只要大約100元即可。
本解決方案主要包括:
- 通過ISATAP隧道使用IPv6
- 直接翻BEEP牆
- 離線下載
- 一個比較靠譜的DNS
如果讀者對路由器有所瞭解,很可能會聽說過OpenWrt這個東西。
OpenWrt是什麼?
OpenWrt是適合於嵌入式設備的一個Linux發行版。
相對原廠固件而言,OpenWrt不是一個單一、靜態的固件,而是提供了一個可添加軟件包的可寫的文件系統。這使使用者可以自由的選擇應用程序和配置,而不必受設備提供商的限制,並且可以使用一些適合某方面應用的軟件包來定製你的設備。對於開發者來說,OpenWrt是一個框架,開發者不必麻煩的構建整個固件就能得到想要的應用程序;對於使用者來說,這意味着完全定製的能力,與以往不同的方式使用設備。
以上摘自Wikipedia。
根據這段描述,我們知道,OpenWrt是一個Linux發行版,因此理論上幾乎任何事情都可以通過OpenWrt來完成。但實際上,受到設備的限制(包括組件和性能等方面),人們通常會從更實際的角度考慮,它能做什麼。
除了本文開始列出的一些功能外,在網上也能找到一些有趣的小玩意,包括遙控小車、視頻監控等。當然,考慮到我們的實際需求,本文將不對這些新奇的想法展開描述。
路由器的選擇
可以安裝OpenWrt的路由器有很多,完整的列表可以在這裏找到:
http://wiki.openwrt.org/toh/start
在挑選路由器前,我們需要再次明確我們的需求:
- 不怕斷電
- 能裝OpenVPN等程序
市面上有電池的路由器還是有一些的,例如TP-Link的MR11U、它的馬甲——Mercury M301等。
而能裝一些程序則是一個比較高的要求,因爲通常路由器的Flash都很小,主流容量是4M,個別路由器甚至只有2M。這給我們在上面安裝一個操作系統,再裝一些程序帶來了比較大的困難。因此,在一些論壇,經常可以看到有人動手改裝路由器,換大一些的Flash,並增加內存。
這一次,我選擇的是淘寶上,有人改裝過的Mercury M301,改裝後的Flash有16M,內存有64M,足夠滿足我們的全部需求。
預編譯OpenWrt
在網上可以下載到很多人編譯好的OpenWrt,但它們並不滿足我們的需求。所以必須自行編譯OpenWrt。
如果讀者有過編譯嵌入式Linux內核或其他嵌入式程序的經驗,那麼編譯OpenWrt的體驗則會相當好。我們不需要去找老舊的交叉編譯器和舊版Linux內核,只需要使用簡單的Make命令,即可編譯出一個OpenWrt出來。
編譯的教程在http://wiki.openwrt.org/doc/howto/buildroot.exigence,簡單的流程如下:
1. 爲了避免不必要的麻煩,裝一個32位版本的Ubuntu,分區容量建議至少15GB。
2. 安裝subversion和build tools,因爲OpenWrt是存放在SVN上的。
$ sudo apt-get update
$ sudo apt-get install subversion build-essential
3. 使用SVN下載源碼。
$ mkdir ~/openwrt
$ cd ~/openwrt
$ svn co svn://svn.openwrt.org/openwrt/trunk/
$ cd trunk
4. 下載安裝feeds,feeds是OpenWrt的包。
$ ./scripts/feeds update -a
$ ./scripts/feeds install -a
5. 依次執行以下命令以完成配置:
$ make defconfig
$ make prereq
$ make menuconfig
此處可能會遇到一些包的缺失信息,只需要按照提示使用apt-get安裝好即可。
6. 執行make來編譯。
對於這個流程,有一些問題需要加以說明:
- 從SVN上下載源碼和feeds的文件大概有500MB,在make的時候還會下載大量包(根據menuconfig的選項而不同),因此請儘量使用一個快速的網絡。
- make的時候,很可能會因爲網絡的原因無法下載到需要的包而導致錯誤,這個時候,請使用
make V=99編譯,可以看到是哪個包下載失敗,然後自行去網上找到這個包,放置在./dl目錄下。 - 可以使用
make -j n(把n替換成CPU線程數+1)來多線程編譯,但這樣可能會難以找到錯誤的地方。 - 流程第5步中的
make menuconfig中需要選擇包,我們在此時只要選擇好路由器的型號,並選中IPv6下的radvd,其他的可以先不選擇。這是因爲,只有在第一次make的時候,編譯腳本纔會去網上下載Linux內核源碼和相關的包,而我們接下來需要修改一些源碼。 - 修改openvpn的編譯選項,以便openvpn能從文件中讀取用戶名和密碼:
打開
./package/feeds/packages/openvpn-devel/Makefile文件,在define Build/Configure段的若干選項中(例如在「--enable-small」之後)增加一行「--enable-password-save」。
要解決的問題
在我們的需求中,有一個需求是很特殊的——IPv6。在清華,IPv6是一個很奇葩的東西。在不少地方,我們可以使用到原生的IPv6,而且這個IPv6地址還是動態的。但遺憾的是,很多時候,IPv6還需要通過一個Portal來認證,而這個Portal總是不能正常工作。因此,很多人會選擇適用ISATAP服務來訪問IPv6。
如果使用Native IPv6,一切都很簡單,我們只需要讓IPv6橋接,讓IPv4 NAT就可以了。
如果使用ISATAP,則問題變得很複雜:
- 一方面,ISATAP得到的IPv6地址的前綴是64位,這意味着我們不能再劃分子網。
- 在RFC的文檔中,IPv6是不支持NAT的。
於是,我們找到了北郵同學的一個解決方案:napt66。這個方案通過Netfilter,實現了一個私有的NAT服務。該方案的部署比較複雜,但幸運的是,作者給出了一個在OpenWrt上部署的文檔。這裏簡單的總結如下(路徑可能略有不同):
1. 修改Linux內核中IPv6轉發的代碼。該文件位於./build_dir/linux-arch/linux-version/net/ipv6/ip6_output.c,將以下兩行註釋掉:
if (net->ipv6.devconf_all->forwarding == 0)
goto error;
更新:Linux 3.7開始,內核提供了對NAT6的原生支持。
2. 修改radvd的探測IPv6轉發參數的代碼。該文件位於./build_dir/target-mips_uClibc-version/radvd/radvd.c,註釋掉以下部分(代碼可能略有不同):
int check_ip6_forwarding(void) {
......
// if (value != 1)
// flog(LOG_DEBUG, \"IPv6 forwarding setting is: %u