修復 OpenWRT 上 Clash(OpenClash)影響 Port Forwarding 的問題

透明代理是個好東西。隨着技術的發展,一些老的工具逐漸體現出各種問題並停止維護,浅羽終於也更換到了基於 Clash 包裝的 OpenClash。雖然 Clash 本身有一些爭議,但配合 OpenClash 使用 LuCI 加上網路上的規則,稍加自定就很獲得不錯的使用體驗,只有一個最大的問題——無論如何都無法連線家中的 VPN 伺服器。

浅羽的 VPN 伺服器並沒有直接架設在 OpenWRT 上,而是位於區域網路內 192.168.0.2 上並透過 port forwarding 接受外部連線。起初浅羽以爲是 port forwarding 及 firewall 設定問題,但幾經調整都無果。偶然查看了 VPN 伺服器的日誌,才發現客戶端其實已經與伺服器取得連線,卻因 TLS handshake timeout 無法成功認證。回想近期對網路的調整,浅羽開始懷疑 Clash 的問題,於是增加了一條 SRC-PORT,1194,DIRECT 規則,並在 Clash 中觀察到也已經直接連線,但客戶端依然提示連線失敗。

透過搜尋工作,浅羽找到並參考了一些相關的問題報告:

其中有回覆提到:

@neroanelli 分析的挺对的,就是包来回的路径不一样。SYN 通过主路由直接发到内网机器上,SYN ACK 发给Clash了,除非 Clash 使用 Raw Socket 特别处理这样的数据包,否则 Clash 没有任何办法处理此类 SYN ACK。

同時有幾位評論者都指出:在 mangle 表中增加規則過濾不希望經過 Clash 的流量可以解決問題。那麼按這個思路在 OpenWRT 上的 iptables 增加一條規則,匹配 host 與 port,使相關流量直接從 PREROUTINGRETURN

# iptables -t mangle -I PREROUTING -p udp -s 192.168.0.2 -m multiport --sports 1194,51820 -j RETURN

確認一下規則生效並且排在 Clash 相關規則前:

# iptables -t mangle -L PREROUTING
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
RETURN     udp  --  192.168.0.2          anywhere             multiport sports openvpn,51820
openclash  all  --  anywhere

再在客戶端嘗試一下就可以成功連線了,同時訪問區域網路及使用透明代理都沒有問題。


總要一邊一邊地刪除加入防火牆規則非常麻煩,如果遇到不在家中、VPN 又連線不上的情況就更惱火了。那麼有什麼辦法可以在 Clash 重新啓動之後自動修改好防火牆規則呢?

研究一下 OpenClash 包裝的規則,主要的啓動和停止都寫在 luci-app-openclash/root/etc/init.d/openclash 中,其中在 set_firewall() 函式中主要處理了防火牆規則的增加。因此在函式最後添加上幾句:

iptables -t mangle -I PREROUTING -p udp -s 192.168.0.2 --sport 1194 -j RETURN
iptables -t mangle -I PREROUTING -p udp -s 192.168.0.2 --sport 51820 -j RETURN

順便在 revert_firewall() 函數最後也添加相反的指令:

   iptables -t mangle -D PREROUTING -p udp -s 192.168.0.2 --sport 51820 -j RETURN
   iptables -t mangle -D PREROUTING -p udp -s 192.168.0.2 --sport 1194 -j RETURN
   # 爲什麼縮進是三個空格?

這樣最起碼 Clash 重新啓動時不會把自己擋在家門外了。

發佈回覆

你的電郵地址並不會被公開。 必要欄位標記為 *

本網誌採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網誌訪客的留言資料