這幾天閒來無事, 學習了一些關於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性能也更優秀配置更加簡單.
不過這種事還早著.