linux 多跳透明網關配置

理論上將適合任何架構,任何系統的linux

網絡拓撲

+-----------+                +------------+                +------------+
|  虛擬機    |   HostOnly     | GatewWay   |   共享上網      | 宿主機      |      wifi
|10.129.37.5|----------------|10.129.3.1  |----------------|10.130.2.1  |----------------INTERNET
|           |           eth1 |10.130.2.1  | eth0           |            |
+-----------+                +------------+                +------------+

虛擬機和Gateway都運行在虛擬機中,虛擬機器將默認網關設置爲GateWay。

最終目標是,將HostOnly的所有網絡流量,都通過代理的形式,發送到遠程服務器。讓虛擬機認爲自己處在遠程網絡中。防止出現意外(例如暴露真實ip)

注意,以下如無說明,都在GateWay中操作

內核的轉發功能

處於安全考慮,Linux默認未允許轉發目的地不是本機的數據包,需要在/etc/sysctl.conf中寫入 net.ipv4.ip_forward = 1以開啓轉發,完成後需要執行sysctl -p刷新。

透明代理配置

主要有兩種配置方法,分別是通過wireguard配置和x2ray。 注意,爲了保證速度,HostOnly網關應該設置爲gateway

wireguard

wg-quick up wg0 # 啓動wireguard 配置 wg啓動一個網卡,並設置系統的默認路由到wg0接口


sudo iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE # 配置出口網卡爲wg0

通過這種方式可以快速將默認網關的流量全部代理到wg中,出口爲國外網絡

然後再安裝dnscrypt-proxy

記得在/etc/dnscrypt-proxy中操作,dnscrypt-proxy生成system 會把當前目錄作爲當前配置文件中的工作目錄

dnscrypt-proxy -service install
dnscrypt-proxy -service start

把配置文件中,監聽0.0.0.0:53 即可

配置開機自連接wireguard

針對iptables項目開機自恢復,參考x2ray下面的那個配置就可以

  1. 在 /etc/systemd/system/ 目錄下創建一個名爲 wg.service 的文件,然後添加以下內容並保存。
[Unit]
Description=Tproxy rule
After=network.target
Wants=network.target

[Service]

Type=oneshot
#注意分號前後要有空格
ExecStart=/usr/bin/wg-quick up wg0 ; /sbin/iptables-restore /etc/iptables/rules.v4

[Install]
WantedBy=multi-user.target
  1. 執行下面的命令使 wg.service 可以開機自動運行。
systemctl enable wg 

x2ray部分

在這裏把vmess改成你自己的真實服務器,其他不要動,尤其是sockopt部分。
sockopt部分同時也添加到你自己的vmess服務器出口配置中

wireguard via X2ray

這樣可以解決wireguard特徵過於明顯,利用x2ray加速的雙重特性。同時也實現了雙重代理

先決知識

我們先來了解以下wireguard全局代理的原理
在ubuntu系統上爲了實現策略路由,配合iptables的mark,引入了ip list。首先會根據ip報文的標籤,決定具體轉發到哪張路由表。也就是說系統同時有了很多路由表。我們看一下啓動wireguard後的系統的路由表和策略表。

在Linux裏,總共可以定義232個優先級的規則,一個優先級別只能有一條規則,即理論上總共可以有條規則。其中有3個規則是默認的
image.png
0:匹配任何條件,查詢路由表local(ID 255),該表local是一個特殊的路由表,包含對於本地和廣播地址的優先級控制路由。rule 0非常特殊,不能被刪除或者覆蓋。

32766:匹配任何條件,查詢路由表main(ID 254),該表是一個通常的表,包含所有的無策略路由。系統管理員可以刪除或者使用另外的規則覆蓋這條規則。

32767:匹配任何條件,查詢路由表default(ID 253),該表是一個空表,它是後續處理保留。對於前面的策略沒有匹配到的數據包,系統使用這個策略進行處理,這個規則也可以刪除。

注:不要混淆路由表和策略:規則指向路由表,多個規則可以引用一個路由表,而且某些路由表可以策略指向它。如果系統管理員刪除了指向某個路由表的所有規則,這個表沒有用了,但是仍然存在,直到裏面的所有路由都被刪除,它纔會消失。

在默認情況下進行路由時,首先會根據規則0 在本地路由表裏尋找路由,如果目的地址是本網絡,或是廣播地址的話,在這裏就可以找到合適的路由;如果路由失敗,就會匹配下一個不空的規則,在這裏只有32766規則,在這裏將會在主路由表裏尋找路由;如果失敗,就會匹配32767規則,即尋找默認路由表。如果失敗,路由將失敗。重這裏可以看出,策略性路由是往前兼容的。

Let’s start from the 32764 rule: as it has a lower number, it’s considered first.

32764:  from all lookup main suppress_prefixlength 0

The rule has no selector, making the kernel consult the main table for every single packet.
If this was the whole rule, every packet would be routed by the main table, never reaching the VPN. This is why the action also contains a suppressor: suppress_prefixlength 0. From the ip-rule(8) man page

suppress_prefixlength NUMBER
    reject routing decisions that have a prefix length of NUMBER or less.

也就是查表並拒絕包。直連網段的路由表,可以被查詢到,而且掩碼肯定不爲0.那麼正常轉發。但是如果是默認路由的話,那麼查詢後的掩碼肯定0,那麼就拒絕轉發。suppress的意思是抑制。

Here “prefix” refers to the address or range of addresses matched in the routing table. So if you have a route for 10.2.3.4, its prefix length is 32 (bits); if you change it to 10.0.0.0/8, the prefix length will be 8.
What is a prefix of length 0 or less? It’s the empty prefix, 0.0.0.0/0, corresponding to the default route. So if the packet was routed by the default route from main, that routing decision is ignored; otherwise, it’s respected.
To summarize, the effect of this rule is to respect all manual routes that the administrator might have added to the main table. However, if the packet didn’t match any of the specific routes, then instead of applying the default route, we’re proceeding to the next rule.

“not from all fwmark 0xca6c lookup 51820”的意思是說,滿足條件“from all fwmark 0xca6c“(wireguard發出的都帶fwmark 0xca6c )請忽略本條規則,繼續往下走,即peer的endpoint地址會走main路。否則,請使用51820路由表,通過wg隧道出去。

對於wg接口發包自帶的0xca6c,繼續走下一條規則,也就是匹配默認路由表,從eth0接口發送出去。

現在我們瞭解一下X2ray的iptables配置原理

根據iptables五鏈三表的順序規則,假如一個包從本機發出,那麼首先會經過OUTPUT鏈,在這裏的mangle表,爲tcp,udp的報文打上標籤爲1。也就是下面兩條命令

iptables -t mangle -A X2RAY_MASK -p udp -j MARK --set-mark 1   # 給 UDP 打標記,重路由
iptables -t mangle -A X2RAY_MASK -p tcp -j MARK --set-mark 1   # 給 TCP 打標記,重路由

給 OUTPUT 鏈的 TCP 和 UDP 打個標記 1(OUTPUT 應用 X2RAY_MASK 鏈)。由於 Netfilter 的特性,在 OUTPUT 鏈打標記會使相應的包重路由到 PREROUTING 鏈上,在已經配置好了 PREROUTING 相關的透明代理的情況下,OUTPUT 鏈也可以透明代理了。其實打標籤,打什麼無所謂,重要的是讓數據包重路由

所以在PREROUTING鏈上,會有下面兩條規則。

iptables -t mangle -A X2RAY -p udp -j TPROXY --on-ip 127.0.0.1 --on-port 12345 --tproxy-mark 1 # 給 UDP 打標記 1,轉發至 12345 端口
iptables -t mangle -A X2RAY -p tcp -j TPROXY --on-ip 127.0.0.1 --on-port 12345 --tproxy-mark 1 # 給 TCP 打標記 1,轉發至 12345 端口

只要從PREROUTING進來的包,就給打個1,然後修改數據包的目的ip到12345,也就是我們x2ray代理的地址。打完標籤後,並修改目的端口,並不會路由。但是這時候會開始匹配策略路由,所以這時候我們要加一條關於標籤1的策略路由,帶有標籤1的數據包轉發到本地。這樣,被修改目的端口的數據都會讓本機處理,也就是嘗試連接本地的12345端口。這時候監聽12345即可(也就是x2ray的任意門)
相關文檔:
https://www.kernel.org/doc/Documentation/networking/tproxy.txt
https://ipset.netfilter.org/iptables-extensions.man.html

ip rule add fwmark 0xca6c table 101
ip route add local 0.0.0.0/0 dev lo table 101

如何配置

在連接wg0的基礎上,既然wg0接口自己已經加標籤了(0xca6c),那麼我們在OUTPUT處,將已經加0xca6c的報文,目的重新修改標籤爲1,觸發報文的重路由,也就是重新到PREROUTING處。當然 x2ray的出口標籤是FF,我們要放行。

iptables -t mangle -I OUTPUT 1 -p udp -j MARK --set-mark 1 -m mark --mark 0xca6c 
iptables -t mangle -A OUTPUT -j RETURN -m mark --mark 0xff

然後添加一條策略路由,針對標籤1的報文,交給本地處理,

ip rule add fwmark 1 table 101
ip route add local 0.0.0.0/0 dev lo table 101

現在wireguard的報文 都會走x2ray了。但是x2ray的報文卻不會出去了,因爲他的標籤是0xff,根據上面我們解釋的規則,又會繼續轉發到wg0口。相當於路由環路。所以我們一定要在wg默認策略前面,新增0xff報文轉發到main

ip rule add fwmark 0xff table main

現在針對PREROUTING進入的報文,有兩種情況,第一別的機器發來的報文,對於這種我們不要做任何處理,因爲給wireguard,讓他做路由交換。第二就是剛纔重路由的,我們轉發到本機的12345,利用上面的策略路由


iptables -t mangle -I PREROUTING 1  -j TPROXY -p tcp --on-port 12345 --tproxy-mark 1 -m mark --mark 1
iptables -t mangle -I PREROUTING 1  -j TPROXY -p udp --on-port 12345 --tproxy-mark 1 -m mark --mark 1 

最終策略路由是這個樣子的

root@router:/home/lzb# ip rule list
0:	from all lookup local
32761:	from all fwmark 0xff lookup main
32762:	from all fwmark 0x1 lookup 101
32763:	from all lookup main suppress_prefixlength 0
32764:	not from all fwmark 0xca6c lookup 51820
32765:	from all fwmark 0x1 lookup 100
32766:	from all lookup main
32767:	from all lookup default

iptables是這樣的

root@router:/home/lzb# iptables -t mangle -L -v -n
Chain PREROUTING (policy ACCEPT 55789 packets, 60M bytes)
 pkts bytes target     prot opt in     out     source               destination
 4521 1297K TPROXY     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            mark match 0x1 TPROXY redirect 0.0.0.0:12345 mark 0x1/0xffffffff
    0     0 TPROXY     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            mark match 0x1 TPROXY redirect 0.0.0.0:12345 mark 0x1/0xffffffff
38039   41M CONNMARK   udp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* wg-quick(8) rule for wg0 */ CONNMARK restore

Chain INPUT (policy ACCEPT 39693 packets, 42M bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 20286 packets, 20M bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 27519 packets, 22M bytes)
 pkts bytes target     prot opt in     out     source               destination
 4521 1297K MARK       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            mark match 0xca6c MARK set 0x1
 6628 1567K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            mark match 0xff

Chain POSTROUTING (policy ACCEPT 47805 packets, 42M bytes)
 pkts bytes target     prot opt in     out     source               destination
 2011  574K CONNMARK   udp  --  *      *       0.0.0.0/0            0.0.0.0/0            mark match 0xca6c /* wg-quick(8) rule for wg0 */ CONNMARK save

ip 策略路由在INPUT OUTPUT中間,和FORWARD在一起

參考
https://sleeplessbeastie.eu/2018/06/21/how-to-create-iptables-firewall-using-custom-chains/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章