GNU/Linux >> Linux の 問題 >  >> Linux

VPN 経由で特定のトラフィックのみをルーティングする

あなたが求めているものはそうではありません 存在。これが、あなたが見つけた回答に満足していない理由です (そのうちのいくつかはおそらく私のものです):それらはすべて 回避策 を提案しています 、単純であれ複雑であれ、真の解決策ではありません。

説明させてください。すべての OS でのルーティングは、宛先アドレスによって決定されます。複数の経路がある場合もありますが、それらの選択は、接続を呼び出すアプリケーションに基づくのではなく、単に宛先アドレスに基づいて行われます。終止符。

重要な例を挙げましょう。 VPN クライアントがそのサーバーへの接続を確立した後でも、VPN 外の特定のサイト (example.org など) に接続をルーティングすることができます。ただし、その特別なアドレスに到達しようとするすべてのアプリケーションは、VPN の外部にルーティングされます。一部のアプリケーションが VPN を介して example.org に移動し、他のアプリケーションが VPN の外部を通過することはできません。

Linux カーネルでは、ソース ルーティングが可能になり、状況はより豊かになります。これは、2 つ以上のルーティング テーブルを持つことができ、宛先アドレスではなく、ソース アドレスに基づいてそれらを選択できることを意味します。

重要な例:私の PC には 2 つの外線があり、2 つの異なるパブリック IP があります。どちらのインターフェイスからも連絡できます。特定の接続への返信は、接続が入ってきたのと同じインターフェイスを通過することが重要です。そうしないと、接続を開始した人に到達したときに無関係として破棄されます。これがソース ルーティングです。

当然のことながら、私たちが開始する接続についてはどうですか? openssh クライアントなど、一部のアプリではバインド アドレスを指定できます:

<ブロック引用>

-b bind_address

ローカル マシンの bind_address を接続の送信元アドレスとして使用します。複数のアドレスを持つシステムでのみ有用です。

それらの場合、1 つのインスタンスが VPN を通過し (ルーティング テーブル 1 など)、別のインスタンスが VPN の外に出ても問題ありません (ルーティング テーブル 2 など)。しかし、Firefox などの他のアプリは、特定のソース IP アドレスにバインドするのが難しいことで知られているだけでなく (ただし、非常に賢い回避策については、こちらを参照してください)、バインドしないという点で意地悪で厄介です。 それぞれが異なる送信元アドレスにバインドされた 2 つのコピーを同時に実行できます。言い換えると、上記のトリックのおかげで、あるインスタンスを選択した送信元アドレスにバインドするように強制できますが、別のバージョンのインスタンスを他の送信元アドレスにバインドすることはできません。

これは、回避策を使用する理由を説明しています。それらはすべて、PC の残りの部分とは別のネットワーク スタックで動作するという同じ考えに基づいています。そのため、複雑さのおおよその降順で、VM、Docker、コンテナー、名前空間を持つことができます。それぞれに 1 つ以上のルーティング テーブルがありますが、それぞれ (VM/dockers/containers/namespaces) の複数のインスタンスを持つことができ、自由に混合することもできます。

回避策の 1 つにまだ関心があるのではないでしょうか?

編集:

最も簡単な回避策は、ネットワーク名前空間です。以下のスクリプトは、NNS のすべての必要な側面を処理します。 、しかし、あなたは好きなことをします) 18 、次に 20 、次のように使用できます:

       newns NAMESPACE_NAME start
       newns NAMESPACE_NAME stop

37 を開きます あなたのために(これは私が xterm が動作するのが好きだからですが、他のものを使いたい場合は変更できます)、新しい名前空間に属しています。 xterm 内から、必要に応じて vpn を開始し、ゲームを開始できます。次のコマンドを使用して、VPN を使用していることを簡単に確認できます:

    wget 216.146.38.70:80 -O - -o /dev/null | cut -d" " -f6 | sed 's/<\/body><\/html>//'

これにより、パブリック IP が返されます。 xterm で VPN をセットアップした後、他のウィンドウでパブリック IP が異なることを確認できます。 254 の異なる NNS と異なる接続を使用して、最大 254 の xterm を開くことができます。

#!/bin/bash

#
# This script will setup an internal network 10.173.N.0/24; if this causes
# any conflict, change the statement below.

export IP_BASE=10.173

# It will open an xterm window in the new network namespace; if anything
# else is required, change the statement below.

export XTERM=/usr/bin/xterm

# The script will temporarily activate ip forwarding for you. If you
# do not wish to retain this feature, you will have to issue, at the 
# end of this session, the command
# echo 0 > /proc/sys/net/ipv4/ip_forward 
# yourself. 

 ###############################################################################

 WHEREIS=/usr/bin/whereis

 # First of all, check that the script is run by root:


 [ "root" != "$USER" ] && exec sudo $0 "[email protected]"

 if [ $# != 2 ]; then
    echo "Usage $0 name action"
    echo "where name is the network namespace name,"
    echo " and action is one of start| stop| reload."
    exit 1
 fi

 # Do we have all it takes?

 IERROR1=0
 IERROR2=0
 IERROR3=0
 export IP=$($WHEREIS -b ip | /usr/bin/awk '{print $2}')
 if [ $? != 0 ]; then
    echo "please install the iproute2 package"
    IERROR1=1
 fi

 export IPTABLES=$($WHEREIS -b iptables | /usr/bin/awk '{print $2}')
 if [ $? != 0 ]; then
    echo "please install the iptables package"
    IERROR2=1
 fi

 XTERM1=$($WHEREIS -b $XTERM | /usr/bin/awk '{print $2}')
 if [ $? != 0 ]; then
    echo "please install the $XTERM package"
    IERROR3=1
 fi
 if [ IERROR1 == 1 -o IERROR2 == 1 -o IERROR3 == 1 ]; then
    exit 1
 fi

 prelim() {

 # Perform some preliminary setup. First, clear the proposed 
 # namespace name of blank characters; then create a directory
 # for logging info, and a pid file in it; then determine 
 # how many running namespaces already exist, for the purpose
 # of creating a unique network between the bridge interface (to 
 # be built later) and the new namespace interface. Lastly, 
 # enable IPv4 forwarding. 

    VAR=$1
    export NNSNAME=${VAR//[[:space:]]}

    export OUTDIR=/var/log/newns/$NNSNAME

    if [ ! -d $OUTDIR ]; then
            /bin/mkdir -p $OUTDIR
    fi
    export PID=$OUTDIR/pid$NNSNAME

    # Find a free subnet

    ICOUNTER=0
    while true; do
            let ICOUNTER=ICOUNTER+1
            ip addr show | grep IP_BASE.$ICOUNTER.1 2>&1 1> /dev/null
            if [ ! $? == 0 -a $ICOUNTER -lt 255 ]; then
                    export Nns=$ICOUNTER
                    break
            elif [ ! $? == 0 -a $ICOUNTER -gt 254 ]; then
                    echo "Too many open network namespaces"
                    exit 1
            fi
    done
    if [ $Nns == 1 ]; then
            echo 1 > /proc/sys/net/ipv4/ip_forward
    fi

 }

 start_nns() {

 # Check whether a namespace with the same name already exists. 

    $IP netns list | /bin/grep $1 2> /dev/null
    if [ $? == 0 ]; then
            echo "Network namespace $1 already exists,"
            echo "please choose another name"
            exit 1
    fi

    # Here we take care of DNS

    /bin/mkdir -p /etc/netns/$1
    echo "nameserver 8.8.8.8" > /etc/netns/$1/resolv.conf
    echo "nameserver 8.8.4.4" >> /etc/netns/$1/resolv.conf
                                                                           

    # The following creates the new namespace, the veth interfaces, and
    # the bridge between veth1 and a new virtual interface, tap0.
    # It also assigns an IP address to the bridge, and brings everything up

    $IP netns add $1
    $IP link add veth-a$1 type veth peer name veth-b$1
    $IP link set veth-a$1 up
    $IP tuntap add tap$1 mode tap user root
    $IP link set tap$1 up
    $IP link add br$1 type bridge
    $IP link set tap$1 master br$1
    $IP link set veth-a$1 master br$1
    $IP addr add $IP_BASE.$Nns.1/24 dev br$1
    $IP link set br$1 up

    # We need to enable NAT on the default namespace

    $IPTABLES -t nat -A POSTROUTING -j MASQUERADE

    # This assigns the other end of the tunnel, veth2, to the new 
    # namespace, gives it an IP address in the same net as the bridge above, 
    # brings up this and the (essential) lo interface, sets up the 
    # routing table by assigning the bridge interface in the default namespace
    # as the default gateway, creates a new terminal in the new namespace and 
    # stores its pid for the purpose of tearing it cleanly, later. 

    $IP link set veth-b$1 netns $1
    $IP netns exec $1 $IP addr add $IP_BASE.$Nns.2/24 dev veth-b$1
    $IP netns exec $1 $IP link set veth-b$1 up
    $IP netns exec $1 $IP link set dev lo up
    $IP netns exec $1 $IP route add default via $IP_BASE.$Nns.1
    $IP netns exec $1 su -c $XTERM $SUDO_USER &
    $IP netns exec $1 echo "$!" > $PID



}

stop_nns() {

# Check that the namespace to be torn down really exists

    $IP netns list | /bin/grep $1 2>&1 1> /dev/null
    if [ ! $? == 0 ]; then
            echo "Network namespace $1 does not exist,"
            echo "please choose another name"
            exit 1
    fi

    # This kills the terminal in the separate namespace, 
    # removes the file and the directory where it is stored, and tears down
    # all virtual interfaces (veth1, tap0, the bridge, veth2 is automatically
    # torn down when veth1 is), and the NAT rule of iptables. 

    /bin/kill -TERM $(cat $PID) 2> /dev/null 1> /dev/null
    /bin/rm $PID
    /bin/rmdir $OUTDIR
    $IP link set br$1 down
    $IP link del br$1
    $IP netns del $1
    $IP link set veth-a$1 down
    $IP link del veth-a$1
    $IP link set tap$1 down
    $IP link del tap$1
    $IPTABLES -t nat -D POSTROUTING -j MASQUERADE
    /bin/rm /etc/netns/$1/resolv.conf
    /bin/rmdir /etc/netns/$1

}


case $2 in
    start)
            prelim "$1"
            start_nns $NNSNAME
            ;;
    stop)
            prelim "$1"
            stop_nns $NNSNAME
            ;;
    reload)
            prelim "$1"
            stop_nns $NNSNAME
            prelim "$1"
            start_nns $NNSNAME
            ;;
    *)
 # This removes the absolute path from the command name

            NAME1=$0
            NAMESHORT=${NAME1##*/}

            echo "Usage:" $NAMESHORT "name action,"
            echo "where name is the name of the network namespace,"
            echo "and action is one of start|stop|reload"
            ;;
 esac

必要に応じて、

を使用して、新しいネットワーク名前空間内でデスクトップ全体を起動することもできます。
            sudo startx -- :2 

Alt を使用して検索できます +Ctrl +Fn 、ここで Fn は F1、F2、....- のいずれかです。

注意点を 1 つ追加する必要があります。名前空間内での DNS 処理には少しバグがあります。しばらくお待ちください。


Linux
  1. すべてのインターネットトラフィックがVPNを通過するだけであることを確認する方法は?

  2. STDERR のみをフィルタに通す

  3. SSH を介してすべてのネットワーク トラフィックをトンネリングするにはどうすればよいですか?

  1. 特定のサブネット (ソース IP) のみを特定のインターフェイスにルーティングする方法は?

  2. iptables を使用して http トラフィックを別の IP アドレスに転送する

  3. Linux ネットワーク トラフィックが eth0 のみを通過するのはなぜですか?

  1. Linux で、特定の宛先ホストへのルートに使用されているネットワーク インターフェイスと送信元 IP アドレスを確認するにはどうすればよいですか?

  2. tc を使用してパケットを 1 つの IP アドレスだけに遅延させる

  3. 特定のホストへのルートのインターフェイスを見つける