前言
RT-AC68U 使用PPPoE拨号上网,但是分配的IP是100.64.204.111, 看着像公网IP实际却是Carrier-grade NAT.
现在需要将RT-AC68U与一台在公网的EdgeRouter使用OpenVPN Site-to-Site连接起来,并在RT-AC68U端实现policy-based routing。
需要让RT-AC68U下的所有设备能访问EdgeRouter LAN的网络,并根据需求透过VPS访问指定互联网。
本实验参考下列文章:
Set up OpenVPN Site-to-Site on UBNT EdgeRouter Lite
EdgeRouter OpenVPN Connectivity Monitor
EdgeRouter 策略路由实现分析
EdgeRouter Policy Based Routing Using DNSMASQ IPSET
环境准备
RT-AC68U
系统:Merlin 380.68_4
公网:无公网IP
LAN:192.168.1.0/24
OpenVPN:OpenVPN端IP 10.99.100.4
EdgeRouter
系统:1.9.7+
公网:域名 edgerouter.rst.im
LAN:192.168.2.0/24
OpenVPN:端口 UDP/1194,OpenVPN端IP 10.99.100.3
OpenVPN
UDP
共享密钥模式
OpenVPN Site-to-Site VPN
EdgeRouter端OpenVPN配置
操作模式下生成密钥
1 |
generate vpn openvpn-key /config/auth/openvpn-test-secret |
配置模式下参考如下配置
1 2 3 4 5 6 7 8 9 10 11 |
ubnt@ubnt# show interfaces openvpn vtun3 local-address 10.99.100.3 { } local-port 1194 mode site-to-site openvpn-option --persist-tun openvpn-option --persist-key openvpn-option "--user nobody" openvpn-option "--group nogroup" remote-address 10.99.100.4 shared-secret-key-file /config/auth/openvpn-test-secret |
RT-AC68U端配置
路由界面,“高级设置”=>“VPN”=>“VPN客户端”=>“OpenVPN”。
Client control
Select client instance:选择一个客户端配置,这里选了Client 1。
Basic Settings
Description:描述,随便填。
Start with WAN:选“是”,这样PPPoE拨号成功后会自动连VPN。
接口类型:TUN
通信协议:UDP
Server Address and Port:地址 edgerouter.rst.im,端口 1194
防火墙:自动/Automatic
验证模式:Static Key,此处点击右侧“Content modification of Keys & Certificates.”,将 /config/auth/openvpn-test-secret 里的内容,贴进“Static Key”去,仅粘贴内容 —– BEGIN xxx —– / —– END xxx —– 。(包括这两行线)
Auth digest:Default
Create NAT on tunnel:是
Local/remote endpoint addresses:第一个框本地IP 10.99.100.4,第二个框EdgeRouter的OpenVPN端IP 10.99.100.3。
Advanced Settings
压缩:Disabled
其他默认。
自定义设置
1 2 3 4 5 |
float ping 10 ping-restart 20 ping-timer-rem route 192.168.2.0 255.255.255.0 |
Policy-Based Routing on Asus Merlin
从EdgeRouter端考虑,需要将从OpenVPN Tunnel过来的流量自动筛选转发到VPS对应的设备,所以上述的EdgeRouter的配置会变成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
openvpn vtun3 { firewall { in { modify AUTO_VPN } } local-address 10.99.100.3 { } local-port 1194 mode site-to-site openvpn-option --persist-tun openvpn-option --persist-key openvpn-option "--user nobody" openvpn-option "--group nogroup" remote-address 10.99.100.4 shared-secret-key-file /config/auth/openvpn-test-secret } |
RT-AC68U端,需要配置PBR规则,需要对OpenVPN Tunnel的设备开启NAT(虽然上边勾选了,但是实测有问题,所以下边的具体配置会写命令解决)。
在RT-AC68U的OpenVPN配置页面,“Redirect Internet traffic”设置为“Policy Rules(strict)”,
添加两条PBR规则:
1 2 |
Source IP=0.0.0.0, Destination IP=192.168.2.0/24,Iface=VPN Source IP=0.0.0.0, Destination IP=8.8.0.0/16, Iface=VPN |
完成这两项,路由的ip rules里就会多两条:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
admin@RT-AC68U:/tmp/home/root# ip rule list 0: from all lookup local 10101: from all to 8.8.0.0/16 lookup ovpnc1 10102: from all to 192.168.2.0/24 lookup ovpnc1 32766: from all lookup main 32767: from all lookup default admin@RT-AC68U:/tmp/home/root# cat /etc/iproute2/rt_tables 100 wan0 111 ovpnc1 112 ovpnc2 113 ovpnc3 114 ovpnc4 115 ovpnc5 200 wan1 |
参考之前的文章,EdgeRouter 策略路由实现分析,我需要做的是,增加一条ip rule,把iptables标记过的流量直接转发到ovpnc1,再用iptables应用规则去标记LAN的请求。
基本命令如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 添加一条ip rule,把特定fwmark的流量转发到ovpnc1的路由表 ip rule add pref 6 fwmark 0x3000000/0x7f800000 table ovpnc1 # 创建一个自动转发的目标IP列表,担心AC68U的内存问题,所以设置了3600秒的过期时间 ipset create PBR_DNS hash:ip timeout 3600 # 创建一个 自动转发的来源IP列表 ipset create PBR_SRC hash:ip # 在tun11上开启NAT iptables -t nat -A POSTROUTING -o tun11 -j MASQUERADE # 加载模块 modprobe xt_set # 请求目标IP在PBR_DNS时,打标记 iptables -t mangle -A PREROUTING -i br0 -m set --match-set PBR_DNS dst -j MARK --set-xmark 0x3000000/0x7f800000 # 请求来源IP在PBR_SRC时,打标记 iptables -t mangle -A PREROUTING -i br0 -m set --match-set PBR_SRC src -j MARK --set-xmark 0x3000000/0x7f800000 |
直接使用 iptables 调用 ipset 会出现如下错误:
iptables: No chain/target/match by that name.
需要先 modprobe xt_set。
由于iptables命令每次重启都要执行,所以需要开启RT-AC68U的JFFS,并在“系统管理”,“系统设置”里,开启“Enable JFFS custom scripts and configs”。开启之后的另外一个好处是可以自动增加额外的dnsmasq配置,这部分参考Setup WPAD on Asus Merlin。
开启ssh后,ssh到RT-AC68U
1 2 |
touch /jffs/scripts/openvpn-event chmod +x /jffs/scripts/openvpn-event |
编辑内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
#!/bin/sh DEFAULT_DEV=tun11 DEFAULT_LOCAL_IP=10.99.100.4 DEFAULT_REMOTE_IP=10.99.100.3 DEV=${1:-$DEFAULT_DEV} BR0=br0 FWMARK=0x3000000/0x7f800000 IPRULE=6 LOCAL_IP=${4:-$DEFAULT_LOCAL_IP} REMOTE_IP=${5:-$DEFAULT_REMOTE_IP} # Register a cron job cru a 1 "* * * * * /bin/sh /jffs/scripts/openvpn-event $DEV A A $LOCAL_IP $REMOTE_IP" test_remote_ip() { ping -c2 -W1 $1 >/dev/null 2>&1 } CONNECTED=$(test_remote_ip $REMOTE_IP) echo $* >> /tmp/ove.log if $CONNECTED; then echo 'connected' >> /tmp/ove.log else echo 'disconnected' >> /tmp/ove.log fi ip rule del pref $IPRULE modprobe xt_set if $CONNECTED ; then ip rule list |grep ^"${IPRULE}:" >/dev/null 2>&1 || ip rule add pref $IPRULE fwmark $FWMARK table ovpnc1 ipset create PBR_DNS hash:ip timeout 3600 ipset create PBR_SRC hash:ip iptables-save | grep "\-A POSTROUTING -o $DEV -j MASQUERADE" >/dev/null 2>&1 || iptables -t nat -A POSTROUTING -o $DEV -j MASQUERADE iptables-save | grep "\-A PREROUTING -i $BR0 -m set --match-set PBR_DNS dst -j MARK" >/dev/null 2>&1 || iptables -t mangle -A PREROUTING -i $BR0 -m set --match-set PBR_DNS dst -j MARK --set-xmark $FWMARK iptables-save | grep "\-A PREROUTING -i $BR0 -m set --match-set PBR_SRC src -j MARK" >/dev/null 2>&1 || iptables -t mangle -A PREROUTING -i $BR0 -m set --match-set PBR_SRC src -j MARK --set-xmark $FWMARK else iptables -t nat -D POSTROUTING -o $DEV -j MASQUERADE iptables -t mangle -D PREROUTING -i $BR0 -m set --match-set PBR_DNS dst -j MARK --set-xmark $FWMARK iptables -t mangle -D PREROUTING -i $BR0 -m set --match-set PBR_SRC src -j MARK --set-xmark $FWMARK fi service restart_dnsmasq |
脚本不解释了。
有个坑点,openvpn的up/down scripts使用同一个的时候,代码里无法判定是up还是down,而且每次启动可能都会有1~2次init,停止的时候可能一个有init一个没有。所以最后只能去测试远端IP能否ping通来判定是up还是down。为了避免重复添加规则,所有add的方法都是先检查了规则是否存在再进行添加操作的。
接下来配置dnsmasq。
1 2 3 4 |
# 让dnsmasq加载 /jffs/dnsmasq/ 下的所有配置文件 echo "conf-dir=/jffs/dnsmasq/" > /jffs/configs/dnsmasq.conf.add mkdir /jffs/dnsmasq/ |
参考下边的文件内容,创建自己的配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
server=/facebook.com/8.8.8.8 ipset=/.facebook.com/PBR_DNS server=/facebook.net/8.8.8.8 ipset=/.facebook.net/PBR_DNS server=/facebook.org/8.8.8.8 ipset=/.facebook.org/PBR_DNS server=/fbcdn.net/8.8.8.8 ipset=/.fbcdn.net/PBR_DNS server=/fbcdn.com/8.8.8.8 ipset=/.fbcdn.com/PBR_DNS server=/fbsbx.com/8.8.8.8 ipset=/.fbsbx.com/PBR_DNS server=/fb.me/8.8.8.8 ipset=/.fb.me/PBR_DNS server=/tfbnw.net/8.8.8.8 ipset=/.tfbnw.net/PBR_DNS server=/instagram.com/8.8.8.8 ipset=/.instagram.com/PBR_DNS server=/cdninstagram.com/8.8.8.8 ipset=/.cdninstagram.com/PBR_DNS server=/whatsapp.com/8.8.8.8 ipset=/.whatsapp.com/PBR_DNS server=/whatsapp.net/8.8.8.8 ipset=/.whatsapp.net/PBR_DNS |
执行 service restart_dnsmasq 重启dnsmasq。
其他
有个问题没解决,从EdgeRouter端暂时还没能连上AC68U的ssh/web console,理论上加iptables转发就行了。