最近家里的路由规则越来越复杂,而且越来越好用。正好昨天跟朋友讨论他的家用路由改造方案,所以研究了一下EdgeRouter的策略路由(Policy-based Routing,PBR)的实现。
我家里的路由是EdgeRouter Lite,固件1.9.1.1,这个实现跟固件关系不大。
首先,我们可以参考一下官方的文档:EdgeRouter – Policy-based routing (source address based)
IP规则配置
我的路由里:
1. 把Google的IP段配置到了一个firewall group里,组名是 G1,所有访问G1的流量都会走wg0转发,G1的成员是固定的;
2. 把DNSMASQ的一个域名列表的解析结果加到了另外一个group,G2,所有访问G2的流量都会走wg0转发,如前边所述,G2的成员由dnsmasq解析的结果来动态生成;
3. 把我家的一个单独的网段,设置为组G3,所有来自G3的流量都走wg0转发;后来我写了一个简单的页面,可以支持客户端把自己的IP添加到G3或从G3移除,后话再说。
我的路由上,G1,G2,G3都使用了network-group,配置命令
|
configure set firewall group network-group G3 network 192.168.16.0/24 |
具体实现上,相当于如下的命令:
|
# ipset create G3 hash:net # ipset add G3 192.168.16.0/24 |
路由表
接下来,配置的是route table。
192.168.10.1 是wg0 网络的远端网关地址,wg0本地ip是 192.168.10.50,所以不需要额外配置192.168.10.0/24的设备路由。
|
configure set protocols static table 6 route 0.0.0.0/0 next-hop 192.168.10.1 [edit] |
对应的实现,
|
ip route add table 6 0.0.0.0/0 via 192.168.10.1 |
如果配置使用的wg0是TUN模式,例如openvpn tun,这个时候应该使用interface-route,对应的实现改为 dev xxx。
查看路由表
EdgeRouter的操作模式下
|
root@ubnt:/home/ubnt# show ip route table 6 default via 192.168.10.1 dev wg0 |
对应的实现
|
root@ubnt# ip route show table 6 default via 192.168.10.1 dev wg0 |
防火墙策略
防火墙配置如下
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
|
root@ubnt:/home/ubnt# configure [edit] root@ubnt# show firewall modify AUTO_VPN description "Auto route to vpn based on destination" rule 700 { action modify description "src based routing" modify { table 6 } source { group { network-group G3 } } } rule 800 { action modify destination { group { network-group G1 } } modify { table 6 } } rule 900 { action modify destination { group { network-group G2 } } modify { table 6 } } [edit] root@ubnt# show interfaces ethernet eth0 firewall in { modify AUTO_VPN } [edit] |
上述配置中,我定义了AUTO_VPN的规则,把前边提到的G1, G2, G3配置进来。我的路由LAN口在eth0上,所以对于eth0的流入流量应用了这个AUTO_VPN规则。
对应的实现,需要查看iptables。
|
# iptables-save |grep AUTO_VPN :AUTO_VPN - [0:0] -A AUTO_VPN -m comment --comment AUTO_VPN-700 -m set --match-set G3 src -j UBNT_PBR_6 -A AUTO_VPN -m comment --comment AUTO_VPN-800 -m set --match-set G1 dst -j UBNT_PBR_6 -A AUTO_VPN -m comment --comment AUTO_VPN-900 -m set --match-set G2 dst -j UBNT_PBR_6 -A AUTO_VPN -m comment --comment "AUTO_VPN-10000 default-action accept" -j RETURN -A VYATTA_FW_IN_HOOK -i eth0 -j AUTO_VPN |
继续查看 UBNT_PBR_6 的规则
|
root@ubnt# iptables-save |grep UBNT_PBR_6 :UBNT_PBR_6 - [0:0] -A AUTO_VPN -m comment --comment AUTO_VPN-700 -m set --match-set G3 src -j UBNT_PBR_6 -A AUTO_VPN -m comment --comment AUTO_VPN-800 -m set --match-set G1 dst -j UBNT_PBR_6 -A AUTO_VPN -m comment --comment AUTO_VPN-900 -m set --match-set G2 dst -j UBNT_PBR_6 -A UBNT_PBR_6 -j MARK --set-xmark 0x3000000/0x7f800000 -A UBNT_PBR_6 -j ACCEPT [edit] |
上述规则都在 mangle 里
这里,我们看到了对于 UBNT_PBR_6 的规则,iptables给数据包打了个 0x3000000/0x7f800000 的标记。
从iptables的文档里可以看到:
connmark
This module matches the netfilter mark field associated with a connection (which can be set using the CONNMARK target below).
[!] –mark value[/mask]
Matches packets in connections with the given mark value (if a mask is specified, this is logically ANDed with the mark before the comparison).
而这个规则的使用在 ip rule list 里可以看到
|
root@ubnt# ip rule list 0: from all lookup local 6: from all fwmark 0x3000000/0x7f800000 lookup 6 220: not from all fwmark 0xffffffff lookup 220 32766: from all lookup main 32767: from all lookup default |
添加方法:
|
ip rule add pref 6 fwmark 0x3000000/0x7f800000 table 6 |
回过头来,还得看看 VYATTA_FW_IN_HOOK 这个规则是如何进入的:
|
root@ubnt# iptables-save |grep VYATTA_FW_IN_HOOK :VYATTA_FW_IN_HOOK - [0:0] -A PREROUTING -j VYATTA_FW_IN_HOOK -A VYATTA_FW_IN_HOOK -i eth0 -j AUTO_VPN :VYATTA_FW_IN_HOOK - [0:0] -A FORWARD -j VYATTA_FW_IN_HOOK [edit] |
PREROUTING 在 nat 表里;
FORWARD 在 mangle 表里。
NAT
对于 wg0,或者所有需要流出流量的设备,需要启用nat,才能保证流量正常流入流出。
|
root@ubnt# show service nat rule ... rule 5032 { outbound-interface wg0 type masquerade } [edit] |
对应的实现是 在 nat.POSTROUTING 配置 MASQUERADE
|
-A POSTROUTING -o wg0 -m comment --comment NAT-5032 -j MASQUERADE |
完结
按上述的结构,我们实现了:
1 定义好组的规则
2 从 mangle.PREROUTING 里,把流量都转向 mangle.VYATTA_FW_IN_HOOK
3 从 mangle.VYATTA_FW_IN_HOOK 里筛选 eth0 的入站流量,应用到 mangle.AUTO_VPN
4 从 mangle.AUTO_VPN 匹配1中定义的规则,应用请求到 mangle.UBNT_PBR_6
5 对 mangle.UBNT_PBR_6 的数据包执行 ACCEPT操作,同时标记为 0x3000000/0x7f800000
6 使用 iproute2 添加一个 0.0.0.0/0 的routing table,指向目标设备/IP
7 使用 iproute2 添加一个规则,把 0x3000000/0x7f800000 的数据包指向 6 中添加的routing table
8 对于目标设备,启用 MASQUERADE
Incoming search terms:
|