如何在 Linux 中讓所有流量通過一個介面
我有一個自寫的介面 tun0(基於TUN/TAP),它輸出它接收到的內容。
我需要係統的所有流量都流過這個介面。
介面的作用是:
- 找出可能被審查的數據包並通過隧道傳輸它們。
- 通過所有其他交通不受影響。
正如你猜想的那樣,我正在嘗試建構一個反審查工具。
關於隧道的決定必須在 tun0 程序內進行,
因為只有在那裡我們才能使用受信任的 DNS。
我需要你的幫助來告訴我如何讓所有的流量通過一個自寫的介面 tun0。如果 tun0 需要更改,我要求您提供此類更改。
以下是我如何嘗試讓所有流量通過 tun0 並失敗(ping 失敗)。
編譯
gcc tun0.c
sudo ./a.out
配置
sudo ip addr add 10.0.0.1/24 dev tun0
- 創建表約翰
$ cat /etc/iproute2/rt_tables # # reserved values # 255 local 254 main 253 default 0 unspec # # local # #1 inr.ruhep 200 John
順序很重要:
sudo ip rule add from all lookup John
sudo ip route add default dev tun0 table John
sudo ip rule add iif tun0 lookup main priority 500
$ ip rule 0: from all lookup local 500: from all iif tun0 lookup main 32765: from all lookup John 32766: from all lookup main 35000: from all lookup default
故障排除
sudo tcpdump -i wlp2s0 -qtln icmp
然後ping -I tun0 8.8.8.8
顯示沒有擷取到數據包,這意味著沒有數據包通過iif tun0 lookup main
規則從 tun0 傳輸到 wlp2s0。- 當我替換
tun0
為lo
到處時,它對我有用。也試過
- 關閉反向路徑過濾,
rp_filter=0
在/etc/sysctl.conf
解答疑難解答
iptables -I FORWARD -j LOG --log-prefix "filter/FORWARD " iptables -t nat -I OUTPUT -j LOG --log-prefix "nat/OUTPUT " iptables -t nat -I PREROUTING -j LOG --log-prefix "nat/PREROUTING " iptables -t nat -I POSTROUTING -j LOG --log-prefix "nat/POSTROUTNG " tail -f /var/log/syslog
來自答案的修改來源也在這裡。
因此,在您的配置中,您嘗試發送到網路的所有數據包最初都來自
10.0.0.1
(因為它們正在通過tun0
介面並且其本地地址是10.0.0.1
)。你擷取數據包,到目前為止一切都很好。現在,
tun0
進一步發送數據包。源地址是10.0.0.1
並且您希望數據包通過不同的介面(wlp2s0
在您的情況下)離開。那是路由,所以讓我們先啟用路由:sysctl -w net.ipv4.ip_forward=1
在那之後,如果你看一下
tcpdump
,wlp2s0
你會注意到數據包離開的是源地址10.0.0.1
,而不是 wlan 介面的源地址(我猜是你所期望的)。所以我們需要更改源地址,它被稱為源 NAT。在 linux 中,借助netfilter/iptables很容易:iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.0.1 -j MASQUERADE
還請檢查您的
FORWARD
連鎖店是否有ACCEPT
政策,或者您需要允許轉發,例如:iptables -A FORWARD -i tun0 -o wlp2s0 -s 10.0.0.1 -j ACCEPT iptables -A FORWARD -i wlp2s0 -o tun0 -d 10.0.0.1 -j ACCEPT
現在一切都應該正常工作了:Linux 核心進行路由,它將數據包從
tun0
介面移動到wlp2s0
. netfilter應該將源 IP 更改10.0.0.1
為您wlp2s0
為輸出數據包分配的介面地址。它會記住所有連接,並且當回複數據包返回時(如果有),它會將wlp2s0
分配地址的介面的目標地址更改為10.0.0.1
(“conntrack”功能)。嗯,它應該,但它沒有。看起來,netfilter對這種複雜的路由配置以及同一個數據包首先通過
OUTPUT
鏈然後被路由並進入PREROUTING
鏈的事實感到困惑。至少在 Debian 8 機器上它不起作用。
排除netfilter 故障的最佳方法是該TRACE
功能:modprobe ipt_LOG iptables -t raw -A OUTPUT -p icmp -j TRACE iptables -t raw -A PREROUTING -p icmp -j TRACE
我只啟用了對 ICMP 數據包的跟踪,您可以使用其他過濾器進行調試。
它將顯示數據包經過哪些表和鏈。而且我可以看到數據包沒有進一步進入
FORWARD
鏈(並且它沒有被nat/POSTROUTING
實際執行的鏈擷取SNAT
)。以下是實現這項工作的幾種方法。
方法#1
消除netfilter混淆的最好方法是在應用程序中更改數據包的源 IP 地址
tun0.c
。這也是最自然的方式。我們需要在向外的路上將 10.0.0.1 更改為 10.0.0.2 ,在返回的路上將 10.0.0.2 更改****為 10.0.0.1。我已經修改
tun0.c
了源地址更改程式碼。這是新文件,這是您的tun0.c
. IP 標頭的更改還涉及校驗和校正,因此我從OpenVPN 項目中獲取了一些程式碼。以下是我在乾淨重啟和啟動後執行的完整命令列表tun0_changeip.c
:ifconfig tun0 inet 10.0.0.1/30 up sysctl -w net.ipv4.ip_forward=1 ip route add default dev tun0 table John ip rule add from all lookup John ip rule add from 10.0.0.2 lookup main priority 500 iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.0.2 -j MASQUERADE
請注意,在這種情況下您不需要關閉反向路徑過濾,因為一切都是合法的 -
tun0
只接收和發送屬於其子網的數據包。您也可以執行基於源的路由而不是基於介面的路由。方法#2
可以
SNAT
在數據包到達tun0
介面之前執行此操作。但這不是很正確。在這種情況下,您肯定需要關閉反向路徑過濾:sysctl -w net.ipv4.conf.tun0.rp_filter=0 # It won't work without also changing the "all" value sysctl -w net.ipv4.conf.all.rp_filter=0
現在,做
SNAT
: iptables -t nat -A POSTROUTING -o tun0 -s 10.0.0.1 -j SNAT –to-source ip.address.of.your.wlan.interface在這裡,我們在數據包到達設備之前更改源地址
tun0
。tun0.c
程式碼“按原樣”重新發送這些數據包(更改了源地址),它們通過 wlan 介面成功路由。但是您可能在 wlan 介面上有一個動態 IP 並且想要使用MASQUERADE
(為了不明確指定介面地址)。以下是您可以使用的方法MASQUERADE
:iptables -t nat -A POSTROUTING -o tun0 -s 10.0.0.1 -j SNAT --to-source 10.0.55.1 iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.55.1 -j MASQUERADE
請注意“
10.0.55.1
” IP 地址 - 它是不同的。你可以在這裡使用任何IP,沒關係。如果我們之前更改源 IP,數據包會在介面上到達nat/POSTROUTING
鏈。wlp2s0
現在它不依賴於 wlan 介面的靜態 IP。方法#3
您也可以使用
fwmark
. 這樣你就不需要SNAT
但你只會擷取傳出的數據包:首先我們需要禁用反向路徑過濾,
tun0
因為它會轉發屬於另一個網路的數據包:sysctl -w net.ipv4.conf.tun0.rp_filter=0 # It won't work without also changing the "all" value sysctl -w net.ipv4.conf.all.rp_filter=0 Now let's alter the routing rules a bit: # Delete old rules ip rule del iif tun0 lookup main ip rule del from all lookup John # Packets will start going from wlan interface so they will have source address of it iptables -t mangle -A OUTPUT -o wlp2s0 -j MARK --set-mark 1 ip rule add fwmark 0x1 lookup John
這是在我的 Debian 8 機器上工作的路由和網路過濾器的另一個“hack” ,但我仍然建議採用第一種方法,因為它更自然並且不使用任何 hack。
您也可以考慮將您的應用程序建構為透明代理。我認為這比分析來自 tun 設備的數據包要容易得多。