基于Asus Merlin+RaspberryPI打造无感知科学上网路由
在上一篇文章《基于无预置IP list的GFW IP解锁方法》中讲述了如何通过Iptables自动检测受干扰的IP地址,在这里将进一步将相关代码整合到实际路由器中。前期个人买了一个Asus Merlin AC-87U,本想将Shadowsocks编译进路由器中,直接实现路由器内的透明代理转发,但尝试半天后,始终未能编译。于是考虑用RaspberryPi+Shadowsocks外挂AC-87U下实现路由转发。
具体实现步骤如下:
1. Asus Merlin AC-87U 干扰IP监测+自动策略路由配置
《基于无预置IP list的GFW IP解锁方法》文中已经提到,实现无IP List的受干扰IP监测和路由转发主要分为两个步骤:
- 在Iptables中配置GFW干扰IP监测策略
- 将检测到的干扰IP纳入策略路由中
由于华硕Merlin固件仅支持在特定JFFS分区下进行用户数据读写,同时仅允许在系统启动时在/jffs/scripts
和/jffs/configs
加载指定脚本和配置数据。因此上述两个关键步骤,就需要在/jffs/scripts
目录下的指定脚本中进行配置。具体如下:
1.1 在/jffs/scripts/firewall-start
脚本中配置iptables过滤策略
为了确保受干扰IP监测策略不被其他系统内置策略覆盖或影响,需要在路由器启动后并配置iptables默认策略后,将我们所需要的监测策略加入到Iptables的FORWARD链中,生效后通过iptables-save
查看输出,应该可以看到在FORWARD链中已经增加了我们所需的4条指令。
# Generated by iptables-save v1.4.14 on Thu Sep 21 21:38:26 2017
*filter
:INPUT ACCEPT [7225:1346582]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [7504:1290180]
.....
###################
#一定要确保以下4条FORWARD规则是在FORWARD链的最前端,否则会被后续的规则直接bypass
-A FORWARD -i eth0 -p tcp -m tcp --tcp-flags RST RST -j LOG --log-prefix "GFW_DECT_RST "
-A FORWARD -i br0 -o eth0 -p tcp -m tcp --tcp-flags SYN,ACK SYN -j LOG --log-prefix "GFW_DEBUG "
-A FORWARD -i br0 -o eth0 -p tcp -m tcp --tcp-flags SYN,ACK SYN -m recent --set --name syn_watch_list --rdest
-A FORWARD -i br0 -o eth0 -p tcp -m tcp --tcp-flags SYN,ACK SYN -m recent --rcheck --seconds 15 --hitcount 3 --name syn_watch_list --rdest -j LOG --log-prefix "GFW_DECT_SYN "
####################
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD ! -i br0 -o eth0 -j DROP
-A FORWARD -i eth0 -m state --state INVALID -j DROP
-A FORWARD -i br0 -o br0 -j ACCEPT
-A FORWARD -j NSFW
-A FORWARD -m conntrack --ctstate DNAT -j ACCEPT
-A FORWARD -i br0 -j ACCEPT
.....
COMMIT
# Completed on Thu Sep 21 21:38:26 2017
1.2 在/jffs/scripts/service-start
脚本中配置策略路由
由于在本方案中AC-87U路由器并未内置Shadowsocks,无法实现路由器内的透明代理,因此我们需要将经iptables监测到的疑似受干扰目标ip的下一跳路由调整到装了Shadowsocks的路由器中,也就是本文的RaspberryPi中。
为了实现这个目标,需要借助watch命令每秒钟刷新一次内核日志,过滤出需要做策略路由的ip地址,相关的watch指令,写在所有服务启动后的/jffs/service-start
脚本中:
#export GFW_LOCAL_GATEWAY=[Replace with your free Internat access gateway ip]
export GFW_LOCAL_GATEWAY=192.168.9.137
export GFW_REMOTE_VPN=[Replace with your remote ss-server ip]
#注意需要避免将到VPN路由地址[GFW_REMOTE_VPN]指向RaspberryPi路由器的地址
watch -n 1 dmesg -c|grep GFW_DECT|grep -v $GFW_REMOTE_VPN|\
awk '/GFW_DECT_SYN/{print $5};/GFW_DECT_RST/{print $4}'|\
awk -F= '{if($1=="SRC"){cmd="route -n|grep "$2" >/dev/null 2>&1 || \
route add "$2" gateway "ENVIRON["GFW_LOCAL_GATEWAY"]" >/dev/null 2>&1"} \
else{cmd="route -n|grep "$2" || ping -c 1 -W 1 "$2" >/dev/null 2>&1 || \
route add "$2" gateway "ENVIRON["GFW_LOCAL_GATEWAY"]" >/dev/null 2>&1"}; \
print(cmd);system(cmd)}'
配置完重启路由器后,在电脑上浏览几个被屏蔽的网站,然后在AC-87U中通过route命令进行观察,便可以看到被干扰的IP地址,已正确的加入了策略路由中,转发给RaspberryPi路由器(记录略多哈 :-P ):
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
172.217.5.65 192.168.9.137 255.255.255.255 UGH 0 0 0 br0
50.19.85.98 192.168.9.137 255.255.255.255 UGH 0 0 0 br0
172.217.5.68 192.168.9.137 255.255.255.255 UGH 0 0 0 br0
17.249.28.69 192.168.9.137 255.255.255.255 UGH 0 0 0 br0
39.155.151.5 192.168.9.137 255.255.255.255 UGH 0 0 0 br0
104.19.192.102 192.168.9.137 255.255.255.255 UGH 0 0 0 br0
104.18.55.167 192.168.9.137 255.255.255.255 UGH 0 0 0 br0
74.125.170.72 192.168.9.137 255.255.255.255 UGH 0 0 0 br0
50.19.240.106 192.168.9.137 255.255.255.255 UGH 0 0 0 br0
172.217.5.74 192.168.9.137 255.255.255.255 UGH 0 0 0 br0
74.125.170.74 192.168.9.137 255.255.255.255 UGH 0 0 0 br0
117.121.27.11 192.168.9.137 255.255.255.255 UGH 0 0 0 br0
23.210.109.43 192.168.9.137 255.255.255.255 UGH 0 0 0 br0
......
169.254.39.0 * 255.255.255.0 U 0 0 0 br0
192.168.1.0 * 255.255.255.0 U 0 0 0 eth0
192.168.9.0 * 255.255.255.0 U 0 0 0 br0
127.0.0.0 * 255.0.0.0 U 0 0 0 lo
default 192.168.1.1 0.0.0.0 UG 0 0 0 eth0
2. RaspberryPi+Shadowsocks透明代理
在已编译好Shadowsocks的RaspberryPi中的/etc/rc.local中配置透明转发规则:
#!/bin/sh -e
#
# rc.local
# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi
export GFW_LOCAL_GATEWAY=[Replace with your free Internat access gateway ip]
export GFW_REMOTE_VPN=[Replace with your remote ss-server ip]
sudo ss-nat -s $GFW_REMOTE_VPN -l your_ss_redir_local_port -b $GFW_REMOTE_VPN -u
sudo nohup ss-redir -s $GFW_REMOTE_VPN -p your_ss_server_passwd_listening_port \
-k your_ss_server_passwd -m your_ss_server_crypto_method \
-l your_ss_redir_local_port -b 0.0.0.0 -u
exit 0
至此,AC-87U已经可以与RaspberryPi配合自动监测受干扰的IP地址,并进行策略路由,并进一步进行透明代理转发。
3. Asus Merlin AC-87U DNS策略查询
当然,为了实现自由上网,除对IP地址做策略路由和透明代理外,还需进一步保护DNS不受污染,在这里感谢Felix Yan同学提供的dnsmasq-china-list工具,可以让路由器对不同的域名进行策略查询。
将dnsmasq-china-list压缩包从github上下载后,解压到AC-87U本地的/jffs/dnsmasq目录下
在/jffs/scripts/init-start脚本中配置主机启动后策略DNS解析文件自动拷贝
#!/bin/sh
mkdir /etc/dnsmasq.d
cp /jffs/dnsmasq/*.conf /etc/dnsmasq.d/
- 配置在WAN口启动后(
/jffs/scripts/wan-start
),将/etc/dnsmasq.d/
中的指定域名DNS解析地址调整为WAN口上游分配的DNS IP地址
#!/bin/sh
/jffs/dnsmasq/dnsmasq-update-china-list `cat /tmp/resolv.conf |awk '{print $2}'`
- 在/jffs/configs/目录中创建
dnsmasq.conf.add
文件,对默认dnsmasq启用conf-dir
,并将默认DNS查询地址修改为不受干扰的DNS解析服务器
admin@RT-AC87U:/jffs/configs# cat dnsmasq.conf.add
no-resolv
server=YOUR_TRUSTY_DNS_IP#PORT
conf-dir=/etc/dnsmasq.d
至此,大功告成,Asus Merlin AC-87U+RaspberryPi+Shadowsocks的组合实现了自动识别被干扰IP+策略路由+透明代理+策略DNS解析,再次驰骋在广阔无垠的Internet上。