Linux

如何在 Linux 中讓所有流量通過一個介面

  • December 4, 2017

我有一個自寫的介面 tun0(基於TUN/TAP),它輸出它接收到的內容。

我需要係統的所有流量都流過這個介面。

介面的作用是:

  1. 找出可能被審查的數據包並通過隧道傳輸它們。
  2. 通過所有其他交通不受影響。

正如你猜想的那樣,我正在嘗試建構一個反審查工具。

關於隧道的決定必須在 tun0 程序內進行,

因為只有在那裡我們才能使用受信任的 DNS。

我需要你的幫助來告訴我如何讓所有的流量通過一個自寫的介面 tun0。如果 tun0 需要更改,我要求您提供此類更改。

以下是我如何嘗試讓所有流量通過 tun0 並失敗(ping 失敗)。

編譯

  1. gcc tun0.c
  2. sudo ./a.out

配置

  1. sudo ip addr add 10.0.0.1/24 dev tun0
  2. 創建表約翰
$ cat /etc/iproute2/rt_tables 
#
# reserved values
#
255     local
254     main
253     default
0       unspec
#
# local
#
#1      inr.ruhep

200 John

順序很重要:

  1. sudo ip rule add from all lookup John
  2. sudo ip route add default dev tun0 table John
  3. 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 

故障排除

  1. sudo tcpdump -i wlp2s0 -qtln icmp然後ping -I tun0 8.8.8.8顯示沒有擷取到數據包,這意味著沒有數據包通過iif tun0 lookup main規則從 tun0 傳輸到 wlp2s0。
  2. 當我替換tun0lo到處時,它對我有用。

也試過

  1. 關閉反向路徑過濾,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

在那之後,如果你看一下tcpdumpwlp2s0你會注意到數據包離開的是源地址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

在這裡,我們在數據包到達設備之前更改源地址tun0tun0.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 設備的數據包要容易得多。

引用自:https://unix.stackexchange.com/questions/407214