利用树莓派做旁路网关实现家居全局透明科学上网实践

国庆期间想找点事情做,比如:

使用的工具

unbound + dnscrypt-proxy + shadowsocks-libev

Unbound is a validating, recursive, and caching DNS resolver product from NLnet Labs. It is distributed free of charge in open-source form under the BSD license.

DNSCrypt is a network protocol that authenticates and encrypts Domain Name System (DNS) traffic between the user’s computer and recursive name servers.

Shadowsocks-libev is a lightweight and secure socks5 proxy

原理概要

我们知道 GFW 让我们没法访问 Google 等网站主要有两个原因:

  • DNS 污染,在你访问 google.com 的时候给你返回一个错误的 IP
  • IP 劫持,即使你访问了正确的 IP ,也在出口附近给你丢包,或者重置连接

所以我们需要解决以上两个问题以及配置路由器:

  • 在 DNS 方面:
    • 使 DNS 分流,对于国内的域名直接使用 114DNS 查询,返回本地解析(避免 baidu.com 等网站解析到了海外的 CDN IP 上)
    • Unbound 用来提供缓存,实际的解析会被转发到 dnscrypt-proxy 上完成
    • dnscrypt-proxy 设置的上游都没有使用标准的 DNS 协议,而是 DNS over TLS 等协议从海外的 DNS 服务器上获得正确的 DNS 解析
  • 在 IP 层面:
    • 同时让国内的 IP 就不要走转发,直接连接国内机器,加快速度
    • 在上面 DNS 已经返回了正确结果的情况下,需要将对应的流量通过 Shadowsocks-libev 转发到墙外
  • 路由器配置
    • 设置网关,网关地址为树莓配 IP(首先要为树莓派设置静态 IP)
    • 设置 DHCP 服务下的 DNS 服务 为树莓派的 IP

DNS 解析服务的安装和配置

DNS 分流

使用仓库 dnsmasq-china-list 来做到将国内外 DNS 分流。

下载仓库:dnsmasq-china-list。

git clone https://github.com/felixonmars/dnsmasq-china-list

在仓库目录下生成 unbound 分流配置文件:accelerated-domains.china.unbound.conf。

make unbound

然后把 文件移动到 /etc/unbound/accelerated-domains.china.unbound.conf (仅为了个人方便使用才移动的)。

Unbound

// 安装
apt install unbound

在 Ubuntu 20.04 中,配置文件位于 /etc/unbound/unbound.conf,里面说到该配置会包含所有 /usr/share/doc/unbound/examples 文件夹目录下的 .conf 文件。所以,可以直接在 /etc/unbound/unbound.conf 下添加配置内容,也可以在 examples 目录下新建配置文件,或在已有的示例文件(examples/unbound.conf)里面修改。

// 在 /examples/unbound.conf 下修改的配置(删除了所有被注释掉的行)结果。
server:
        verbosity: 1

        // 表示让 ubound 监听在所有端口上
        interface: 0.0.0.0

        // 表示允许所有的 ip 都能使用 unbound DNS 服务器,不然会被拒绝(permission deny)。
        access-control: 0.0.0.0/0 allow

        // 默认值为 yes,为默认值时 forward 会失败,因为 forward 的地址是:127.0.0.1
        do-not-query-localhost: no

// 国内的 DNS 解析(这个是通过 GitHub 仓库:dnsmasq-china-list,经过命令:make unbound 生成的文件)
include: "/etc/unbound/accelerated-domains.china.unbound.conf"

// 表示请求所有域名时,都会 forward 到 127.0.0.1:5353(dnscrypt-proxy 的配置)
forward-zone:
        name: "."
        forward-addr: 127.0.0.1@5353
        forward-first: no

DNSCrypt-proxy

// 安装
apt install dnscrypt-proxy

/etc/dnscrypt-proxy/dnscrypt-proxy.toml 下配置上游 DNS。做如下修改:

listen_addresses = ['127.0.0.1:5353']    // 指定 dnscrypt 监听地址
server_names = ['geekdns-doh','geekdns-doh-ext']    // 上游 DNS 服务器名

另外,还需在 /lib/systemd/system/dnscrypt-proxy.socket 里修改 dnscrypt-proxy.socket 的监听地址,不然会导致 unbound 无法启动。①

IP 分类和流量转发

ipset

用来保证国内 IP 不会走代理,首先我们需要获得全部国内 IP 段,直接从网上找到对应的脚本并加以改造:

# 创建文件:ipset.sh

# 下载所有的国内 IP
#!/bin/bash
wget --no-check-certificate -O- 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest'| awk -F\| '/CN\|ipv4/ { printf("%s/%d\n", $4, 32-log($5)/log(2)) }'> /root/ipset/chnroute.txt

echo "ipset -N cidr_cn hash:net" > /root/ipset/ipset_chnroute.sh

while read ip;do
    echo ipset -A cidr_cn $ip
done</root/ipset/chnroute.txt >> /root/ipset/ipset_chnroute.sh

这样会在 /root/ipset/ 下生成一个叫 ipset_chnroute.sh 的文件,执行这个文件即可加入一个叫 cidr_cn 的 ipset ,用于下文中的 IP 分流操作:

# 创建文件:redir.sh

#!/bin/bash
iptables -t nat -N shadowsocks # 保留地址、私有地址、回环地址 不走代理
iptables -t nat -A shadowsocks -d 0/8 -j RETURN
iptables -t nat -A shadowsocks -d 127/8 -j RETURN
iptables -t nat -A shadowsocks -d 10/8 -j RETURN
iptables -t nat -A shadowsocks -d 169.254/16 -j RETURN
iptables -t nat -A shadowsocks -d 172.16/12 -j RETURN
iptables -t nat -A shadowsocks -d 192.168/16 -j RETURN
iptables -t nat -A shadowsocks -d 224/4 -j RETURN
iptables -t nat -A shadowsocks -d 240/4 -j RETURN # 以下IP为局域网内不走代理的设备IP

iptables -t nat -A shadowsocks -s 192.168.1.200 -j RETURN # 这里 192.168.1.200 是树莓派在局域网内的 IP

# 大陆地址不走代理的
iptables -t nat -A shadowsocks -m set --match-set cidr_cn dst -j RETURN 

iptables -t nat -A shadowsocks ! -p icmp -j REDIRECT --to-ports 8888
iptables -t nat -A OUTPUT ! -p icmp -j shadowsocks
iptables -t nat -A PREROUTING ! -p icmp -j shadowsocks

流量转发

shadowsocks-libev:我们需要用到的是 ss-redir 和 iptables 用于将发往树莓派的所有流量通过 Shadowsocks 转发出去,使用 libev 版本的原因是 ss-redir 只在这个版本中存在。

// 安装
apt install shadowsocks-libev

然后参考官网 ss-local 的配置方式写出一个服务器 json 文件,使用:

ss-redir -c /path/to/local.json -v

启动 ss-redir,这里记住 json 文件中的 local_port,可以参考 Linux 开启热点并转发代理流量使 Blackberry Passport 出墙

路由器配置

登录路由器,在路由器 DHCP 服务下修改网关和 DNS 服务地址为树莓派的 IP 地址即可。

总结

问题总结

① 配置好了 unbound 和 dnscrypt-proxy 之后发现重启不了了?

通过日志发现,有进程(dnscrypt-proxy.socket)占用了 unbound 默认使用的 53 端口,因此修改了它的监听端口,但不要改为和 dnscrypt-proxy.service 一样,不然 dnscrypt-proxy 也会无法启动。

技术总结

现在网上有很多教程都是关于用树莓派开热点然后让连接上树莓派热点的用户实现自动翻(而且很多人都是互相抄导致所有树莓派相关的教程都是安装 hostapd …),树莓派自带的无线网卡性能并不好,所以本文分享一个用树莓派作为旁路网关的方式实现,希望可以帮助到有类似需求的同伴们。

参考

  1. 利用shadowsocks打造局域网翻墙透明网关

Leave a Reply

Your email address will not be published. Required fields are marked *