这几天闲来无事, 学习了一些关于iptables的知识, 同时也了解了一下OpenClash在OpenWRT上是怎么对经过网关的流量做透明代理的.
首先是Filter规则, filter是一个专门的流量过滤器, 它是不做任何流量处理的, 只负责拦截.
1Chain INPUT (policy ACCEPT)
2target prot opt source destination
3openclash_wan_input all -- anywhere anywhere ! match-set localnetwork src
4ACCEPT all -- anywhere anywhere policy match dir in pol ipsec proto esp
5SOCAT all -- anywhere anywhere
6ACCEPT all -- anywhere anywhere /* !fw3 */
7input_rule all -- anywhere anywhere /* !fw3: Custom input rule chain */
8ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED /* !fw3 */
9syn_flood tcp -- anywhere anywhere tcp flags:FIN,SYN,RST,ACK/SYN /* !fw3 */
10zone_lan_input all -- anywhere anywhere /* !fw3 */
11zone_wan_input all -- anywhere anywhere /* !fw3 */
12zone_VPN_input all -- anywhere anywhere /* !fw3 */
13zone_vpn_input all -- anywhere anywhere /* !fw3 */
14zone_docker_input all -- anywhere anywhere /* !fw3 */
这里我们只看第一条目标是openclash_wan_input 的规则简单的解释一下, 所有自外部网络的所有流量(all)转发到 OpenClash 进行处理,但不包括来自本地网络的流量(localnetwork),
1Chain openclash_wan_input (1 references)
2target prot opt source destination
3REJECT udp -- anywhere anywhere multiport dports 7892,7895,9090,7890,7891,7893,7874 reject-with icmp-port-unreachable
4REJECT tcp -- anywhere anywhere multiport dports 7892,7895,9090,7890,7891,7893,7874 reject-with icmp-port-unreachable
然后openclash_wan_input 这个也比较简单, 拒绝所有TCP/UDP目标是7892,7895,9090,7890,7891,7893,7874的流量. 这些端口是clash的一些dns, 透明代理等端口.
上下文连起来就可以知道, 这个filter就是openclash不希望非内部的主机连接clash的端口.
接下来看NAT的规则, NAT可以对数据包的目的地和源地址做修改, 起着转发的作用. 这里是PREROUTING链, 一般是数据包在进入防火墙之前会被放在这里处理.
1Chain PREROUTING (policy ACCEPT)
2target prot opt source destination
3prerouting_rule all -- anywhere anywhere /* !fw3: Custom prerouting rule chain */
4zone_lan_prerouting all -- anywhere anywhere /* !fw3 */
5zone_wan_prerouting all -- anywhere anywhere /* !fw3 */
6zone_VPN_prerouting all -- anywhere anywhere /* !fw3 */
7zone_vpn_prerouting all -- anywhere anywhere /* !fw3 */
8zone_docker_prerouting all -- anywhere anywhere /* !fw3 */
9REDIRECT udp -- anywhere OpenWrt.lan udp dpt:domain redir ports 5352
10REDIRECT udp -- anywhere 192.168.1.5 udp dpt:domain redir ports 5352
11openclash tcp -- anywhere anywhere
openclash自己的是这里表里的最后一条规则. 如果上面的规则都没有命中, 就会走到Openclash这里.
1Chain openclash (1 references)
2target prot opt source destination
3RETURN tcp -- anywhere anywhere tcp spt:1688
4RETURN tcp -- anywhere anywhere tcp spt:1723
5RETURN tcp -- anywhere anywhere tcp spt:openvpn
6RETURN all -- anywhere anywhere match-set localnetwork dst
7REDIRECT tcp -- anywhere anywhere redir ports 7892
来看看openclash.其实这里的规则我不用解释应该也能看得懂. 就不解释了
然后看看nat中的output链, 该链的处理时间是在数据包通过防火墙的时候会被处理.
1Chain OUTPUT (policy ACCEPT)
2target prot opt source destination
3openclash_output all -- anywhere anywhere
非常简单的一条, 所有流量都会流到openclash.
1Chain openclash_output (1 references)
2target prot opt source destination
3RETURN tcp -- anywhere anywhere tcp spt:1688
4RETURN tcp -- anywhere anywhere tcp spt:1723
5RETURN tcp -- anywhere anywhere tcp spt:openvpn
6REDIRECT tcp -- anywhere 198.18.0.0/16 ! owner UID match nobody redir ports 7892
7RETURN all -- anywhere anywhere match-set localnetwork dst
8REDIRECT tcp -- anywhere anywhere ! owner UID match nobody redir ports 7892
然后我们看看这里面的规则.
第一条是如果源端口是1688, 并且是TCP协议, 那么直接返回, 停止后续匹配, RETURN 就起着这样的作用
第二天也是大概同理.
第三条也差不多, 不过openvpn是一个ipset也就是集合, 里面存放了一些用来匹配的主机信息.
第四天是如果目标是198.18.0.0/16 网段, ! owner UID match nobody 是这个数据包的用户不能是nobody, 这个我也不太理解, 外部来的数据包一般的所属用户会是谁? 最后会被转发到7892端口, 这个端口也就是clash的透明代理端口, 至于198.18.0.0/16 这个实际上是我开了fake-ip的原因. 所有的dns都会是在该网段中的地址.
第五条和之前的filter类似, 如果目标连接是本地连接就终止匹配.
最后一条和第四条类似, 这条应该是非fake-ip状态下的规则.
以上就是Openclash对直连情况下的流量做的处理, 还有一种就是流量会经过TUN的时候.
TUN 作为网络层设备, 它可以用来处理 TCP、UDP、ICMP 流量. 它已经在生产环境中进行了广泛的测试和使用 - 您甚至可以用它来玩竞技游戏.
使用 Clash TUN 的最大优势之一是内置支持对操作系统路由表、路由规则和 nftable 的自动管理.
我使用的方案是混合模式, TCP流量走直连, UDP流量走TUN.
这里也看一下Openclash是如何处理UDP流量的.
1root@OpenWrt:~# iptables -t mangle -L
2Chain PREROUTING (policy ACCEPT)
3target prot opt source destination
4openclash udp -- anywhere anywhere
这是mangle表, 这张表所做的工作比filter和nat更细一些, mangle能修改数据包的各种属性. 如标记(mark)、TTL(Time to Live)值、TOS(Type of Service)字段等。
1Chain openclash (1 references)
2target prot opt source destination
3RETURN udp -- anywhere anywhere udp spt:openvpn
4RETURN udp -- anywhere anywhere udp spt:4500
5RETURN udp -- anywhere anywhere udp spt:isakmp
6RETURN udp -- anywhere anywhere udp spt:isakmp
7RETURN udp -- anywhere anywhere udp spt:bootpc
8RETURN all -- anywhere anywhere
9RETURN all -- anywhere anywhere match-set localnetwork dst
10openclash_upnp udp -- anywhere anywhere
11MARK all -- anywhere anywhere MARK set 0x162
上面部分其实没什么好看的, 主要是最后一条, 讲数据包标记为162. mark是策略路由经常使用的一个方法.
接下来我们就需要知道162到底是会被如何路由.
1root@OpenWrt:~# ip rule list
20: from all lookup local
332764: from all fwmark 0x162 lookup 354
432765: from all fwmark 0x162 lookup 354
532766: from all lookup main
632767: from all lookup default
如果数据包的标记等于0x162,那么它们将被路由到表354(lookup 354)。
1root@OpenWrt:~# ip route list table 354
2default dev utun scope link
结束了, 所有进来的流量都会流到utun网卡.
以上就是OpenClash对防火墙做的所有操作.
不过听说近几年nftable有崛起的趋势, 要把iptable代替. 并且nft性能也更优秀配置更加简单.
不过这种事还早着.