web-dev-qa-db-ja.com

Linuxですべてのトラフィックが1つのインターフェースを通過するようにする方法

自己作成インターフェースtunTUN/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. テーブルJohnを作成する

    $ 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

回答から変更されたソースも here です。

12
ilyaigpetrov

したがって、構成では、最初に10.0.0.1から発信されたネットワークに送信しようとするすべてのパケット(tun0インターフェースを経由し、ローカルアドレスが10.0.0.1であるため)。パケットをキャプチャすると、これまでのところすべてが正常です。
今、tun0はさらにパケットを送信します。 送信元アドレス10.0.0.1であり、パケットを別のインターフェース(この場合はwlp2s0)から送信します。 ルーティングなので、最初にルーティングを有効にします。

sysctl -w net.ipv4.ip_forward=1

その後、wlp2s0tcpdumpを確認すると、パケットが送信元アドレス10.0.0.1で送信され、wlanインターフェースの送信元アドレスでは送信されないことに気づくでしょう(期待どおり)私は推測する)。したがって、送信元アドレスを変更する必要があり、それはsource NATと呼ばれます。 Linuxでは、 netfilter/iptables を使用すると簡単です。

iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.0.1 -j MASQUERADE

また、FORWARDチェーンにACCEPTポリシーがあることを確認してください。そうでない場合は、次のようにallow forwardingする必要があります。

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 kernel がルーティングを行い、パケットをtun0インターフェースからwlp2s0に移動します。 netfilter は、ソースIP 10.0.0.1を、出力パケット用のwlp2s0インターフェイスに割り当てられたアドレスに変更する必要があります。すべての接続を記憶し、応答パケットが戻ると(それらの場合)、wlp2s0インターフェースに割り当てられたアドレスの宛先アドレスを10.0.0.1に変更します(「conntrack」機能)。
まあ、そうすべきですが、そうではありません。 netfilter は、この複雑なルーティング構成と、同じパケットが最初にOUTPUTチェーンを通過し、次にルーティングされてPREROUTING chain。少なくとも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チェーンを通過しないことがわかります(実際にSNATを実行するnat/POSTROUTINGチェーンによってキャッチされていません)。
これを機能させるためのいくつかのアプローチを以下に示します。

アプローチ#1

netfilter を混乱させない最善の方法は、tun0.cアプリケーションでパケットのソースIPアドレスを変更することです。また、これは最も自然な方法です。外向きにchange 10.0.0.1 to 10.0.0.2に、帰りに10.0.0.2 to 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

パケットがtun0インターフェースに到達する前にSNATを実行することが可能です。しかし、それはあまり正しくありません。この場合は、必ず reverse path filtering をオフにする必要があります。

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

ここでは、送信元アドレスを変更するだけですbeforeパケットは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

routing netfilter の「ハック」は、Debian 8ボックスで動作しますが、それでも最初のアプローチを使用することをお勧めしますより自然で、ハックを使用しません。


透過プロキシとしてアプリケーションを構築することも検討できます。 tunデバイスからのパケットを分析するよりもはるかに簡単だと思います。

10
tifssoft