清华本科生适用路由器配置指南

发布于2012年11月17日 -

如果你只是需要一个能在熄灯之后使用的路由器,请在网上买一个带电池的路由器,只要大约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