How to build a home soft smart router
为什么要瞎折腾
今年年初买了个机柜放到家里,部署好了 google 的 Go builder 之后,一直忙于工作,都没有时间再折腾,作为一个 “计算机科学家”,平时工作需要经常从网上搬运代码(c+v && c+v), 众所周知,google 搜索的质量比国内的搜索引擎好太多,关键字提取的好第一页就能找到自己想要的内容,但是频繁的进行微皮恩开关还是稍显麻烦,而且还要配置家里的每一个终端,能不能让家里的网络很轻松的访问到某些学习资源呢?
好的程序员一定是懒的,一定是不能吃苦的。
思路
首先需要一个能配置(有 Linux kernel)的路由器,正好朋友最近在考虑换家里的路由器,于是一起研究了下,发现基于 OpenWRT 的设备可以满足我们的需求,于是在网上火速下单了下面这款设备,gl.inet mt1300:
CPU: MT7621A @880MHz RAM: DDR3L 256MB WIFI: 2.4GHz (400Mbps), 5GHz (867Mbps)
从界面高级选项中打开安装 luci,通过 ssh 登录路由器内,安装 wireguard 通过国际 CN2 线路打通到硅谷的隧道,这里自己琢磨,不敢详述。
我们添加下面两条路由来平滑的修改默认路由 (无需删除之前的默认路由,也不会引起网络中断,感谢R):
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.0.1.1 128.0.0.0 UG 0 0 0 wg0
128.0.0.0 10.0.1.1 128.0.0.0 UG 0 0 0 wg0
这样所有的流量都直接从硅谷出去了,但是国内的资源会非常慢,怎么办呢,可以通过路由进行分流,OpenWRT 就是一个开源的 Linux,想怎么写路由都可以,首先我们从 apnic 上下载会最新的 IP 地址文件,把国内的 IP 地址段全部拿出来并转换成路由需要的 CIDR 格式:
curl 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' | grep ipv4 | grep CN | awk -F\| '{ printf("%s/%d\n", $4, 32-log($5)/log(2)) }' > chnroute.txt
一共 8618 条地址块,有点多,我们写个 go 程序看看能不能再合并一下:
package main
import (
"fmt"
"io/ioutil"
"strings"
"github.com/EvilSuperstars/go-cidrman"
)
func main() {
raw, err := ioutil.ReadFile("./chnroute.txt")
if err != nil {
panic(err)
}
lines := strings.Split(string(raw), "\n")
var cidrs []string
for _, l := range lines {
if l == "" {
continue
}
cidrs = append(cidrs, l)
}
newCIDRs, err := cidrman.MergeCIDRs(cidrs)
if err != nil {
panic(err)
}
for _, c := range newCIDRs {
fmt.Printf("%s\n", c)
}
}
合并完为 5434 条,少了 3000 多条,但是感觉还是有点多,不过确实合并不了了,大量的 /22、/23 的地址块无法向上合并了。
到底行不行
直接写个 shell 将 5000 多条路由以静态路由的方式写入配置文件,这样下次重启无需重新配置,OK,重启路由测试。发现路由信号直接消失了,第一反应是完了,需要重置路由器了,之前的 wg 需要重新配置了。过了好久信号回来了,但是无法获取到 DHCP 下发的地址,怀疑是静态路由太多导致 DHCP Server 起不来了,死马当成活马医,直接手写一个 IP,居然 ping 通了网关,进去清理掉了路由,看来性能确实不行啊,那只能是家里存在两个 wifi,一个用于国内资源访问,一个用于访问海外资源,常用办公的电脑链接海外 wifi,台式娱乐机链接到国内的路由器上,看来也能用。
有一天和朋友聊起这个问题,国内的 CIDR 地址块能不能再减少一些,其实如果不是那么精确,合并成一些大一点的 CIDR 其实可能问题也不大,但是要自己写一个合并策略和条件,想着有时间可以搞一下。还和朋友讨论了是不是可以搞一台专业点的路由器提升下性能,比如淘汰下来的 思科 1900 系列,home lab 的组建强调的是节能和静音,你们觉得下面这个东西可能吗?
在咸鱼上翻了好久的路由器,回去又盯着机柜发呆,突然在机柜的角落里看到一层灰的树莓派,emmm,它的性能很强啊,作为 Arm 架构的硬件,也很节能。要不试一试。说干就干,直接在树莓派官网下载系统安装工具,挑一个喜欢的系统安装,我选择的是 Ubuntu,接着安装 wg,导入那让人头疼的 5000 多条路由,看起来没啥问题,也不卡。工作时的 status 如下:
Welcome to Ubuntu 21.10 (GNU/Linux 5.13.0-1008-raspi armv7l)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Tue Dec 28 13:57:25 UTC 2021
System load: 0.08
Usage of /: 8.8% of 28.95GB
Memory usage: 27%
Swap usage: 0%
Temperature: 35.9 C
Processes: 144
Users logged in: 0
IPv4 address for eth0: 10.0.0.10
IPv6 address for eth0: fd6b:bbbf:837b::c1e
IPv6 address for eth0: fd6b:bbbf:837b:0:ba27:ebff:fec0:d41
IPv4 address for wg0: 10.0.1.3
37 updates can be applied immediately.
To see these additional updates run: apt list --upgradable
如果我们使用一个 Linux 来做软路由,记得要把内核的转发打开,在 /etc/sysctl.conf 中添加:
net.ipv4.conf.default.forwarding=1
net.ipv4.conf.all.forwarding=1
记得 sysctl -p 生效,当然还有 NAT with iptables 功能也要开启,这个要使用 iptables 来支持。
iptables -t nat -A POSTROUTING -j MASQUERADE
OK, 一台支持智能分流的树莓派软路由完成配置了,但是目前我们在树莓派上配置的 DNS 是阿里云的多线 DNS: 223.5.5.5,由于众所周知的问题,国内 DNS 多多少少有点问题(如果你不知道就很难看懂),那么能不能直接用国外的 DNS 呢,比如 Google 的 8...8 ?答案是不能,因为很多内容服务商都有基于 DNS 的智能解析,我可不想在国内访问斗鱼时给我调度到国外的 CDN 上去,那么看来 DNS 解析也需要分流了。
总有前人走过的路
在树莓派上安装 dnsmasq 就可以完成 DNS 解析的缓存、分流、拦截等操作,接着树莓派的 resolve 文件调整为:
nameserver 127.0.0.1
nameserver 223.5.5.5
我们默认走本地,然后是国内的 DNS,但是哪些域名需要走国外的 DNS 呢?github 是个好地方,不能写太多,给点提示,聪明的你肯定能找到:
wget https://github.com/cokebar/***2dnsmasq/blob/master/***2dnsmasq.sh
bash ./***2dnsmasq.sh -d 8.*.*.8 -p 53 -o ./dns.conf
最后 reload dnsmasq,OK,你现在可以在一个网络中既能快速的偷学海外学习资料,又能稳定的沉浸在斗鱼的直播中了。对了,有人收我那台 OpenWRT 的路由器吗,兄弟价。