VPN을 통해 특정 트래픽 만 라우팅


11

나는 비슷한 질문을하는 이전 사람들을 찾아 보았지만 주어진 상황에 맞는 답을 아직 얻지 못했다.

Linux (Fedora 22)에서 실행 중이며 유료 VPN 서비스가 있지만 인터넷 트래픽에 VPN을 사용하기 위해 특정 프로그램 만 있으면되며 표준 ISP 연결을 사용하여 다른 모든 것 (예 : 웹 브라우징, 기타)

우리는 이것을 간단하게 만들고 WINE을 통해 실행되는 가장 많이 사용되는 프로그램 인 월드 오브 워크래프트로 제한합니다.

이제 enp10s0 (내 컴퓨터의 eth0의 이상한 이름)을 통한 모든 트래픽을 VPN 서비스를 통해 터널링 할 수 있도록 네트워크 인터페이스를 통해 VPN을 설정했지만 특정 프로그램 (또는 해당 프로그램에서 사용하는 포트) 만 필요합니다. VPN을 통과해야합니다.

터널을 설정하고 VPN을 통해 필요한 포트만 라우팅하고 다른 모든 라우팅은 유지하지 않는 방법은 무엇입니까?


다른 답변으로이 문제를 해결하지 못하는 방법을 설명 할 수 있습니까? 설정에서 고유 한 것은 무엇입니까?
Paul

1
거의 모든 사람들이 이것을 달성하는 다른 방법을 가지고 있으며, 그들 중 누구도 그것을 간단하게 만들지는 않습니다. 일부는 응용 프로그램에 별도의 네임 스페이스를 사용하고, 일부는 터널 인터페이스를 사용하고, 일부는 터미널에서 openvpn을 통해 직접 사용하지만, 내가 찾은 것은 아무도 이것들을 수행하는 해독 가능한 방법을 제공하지 않았습니다.
Josh Raymond

답변:


17

당신이 요구하는 것은 존재 하지 않습니다 . 그렇기 때문에 발견 한 답변 (일부는 아마도 내 것)에 불만족합니다. 모두 간단한 해결책이나 복잡한 해결책이 아닌 해결책 을 제안했습니다 .

설명하겠습니다. 모든 OS에서의 라우팅은 대상 주소에 따라 결정됩니다. 여러 경로가있을 수 있지만 연결을 호출하는 응용 프로그램이 아니라 단순히 대상 주소에 따라 선택됩니다. 마침표.

사소한 예를 드리겠습니다. VPN 클라이언트가 서버에 연결 한 경우 VPN 외부의 특정 사이트 (예 : example.org)로 연결을 라우팅 할 수 있습니다. 그러나 특정 주소에 도달하려는 모든 응용 프로그램은 VPN 외부로 라우팅됩니다. 다른 응용 프로그램이 VPN 외부를 통과하는 동안 일부 응용 프로그램이 VPN을 통해 example.org로 이동할 수는 없습니다.

소스 라우팅을 허용하는 Linux 커널을 사용하면 상황이 더욱 풍부 해집니다. 즉, 둘 이상의 라우팅 테이블을 가질 수 있으며, 둘 중 하나를 선택하면 대상 주소가 아닌 소스 주소를 기반으로 선택됩니다.

사소한 예 : 내 PC에는 두 개의 외부 공용 회선이 있고 두 개의 다른 공용 IP가 있습니다. 두 인터페이스 중 하나를 통해 연락 할 수 있으며, 주어진 연결에 대한 응답이 연결을 통해 온 동일한 인터페이스를 통해 전달되어야합니다. 그렇지 않으면 연결을 시작한 사람에게 도달하면 관련이없는 것으로 폐기됩니다. 이것은 소스 라우팅입니다.

충분합니다. 우리가 시작한 연결은 어떻습니까? 일부 앱에서는 openssh 클라이언트 와 같이 바인드 주소를 지정할 수 있습니다 .

-b bind_address

로컬 시스템에서 bind_address를 연결의 소스 주소로 사용하십시오. 주소가 둘 이상인 시스템에서만 유용합니다.

그들에게는 하나의 인스턴스가 VPN을 통해 (예 : 라우팅 테이블 1) 나가는 반면 다른 인스턴스가 VPN을 통해 (라우팅 테이블 2)하는 데에는 문제가 없습니다. 그러나 Firefox와 같은 다른 응용 프로그램은 특정 소스 IP 주소에 바인딩하는 것이 매우 어려울뿐만 아니라 ( 매우 현명한 해결 방법 은 여기 참조 ), 두 개의 사본을 가질 수 없다는 의미에서 불쾌 합니다. 각각 다른 소스 주소에 바인딩되어 동시에 실행됩니다. 즉, 위에서 언급 한 트릭으로 인해 하나의 인스턴스가 선택한 소스 주소에 바인딩하도록 강요 할 수 있지만 다른 버전의 인스턴스를 다른 소스 주소에 바인딩 할 수 없습니다.

이것은 우리가 대안을 사용하는 이유를 설명합니다. 그것들은 모두 같은 아이디어를 기반으로하며 나머지 PC와는 별도의 네트워크 스택으로 작동한다는 것입니다. 따라서 대략적인 복잡성, VM, 도커, 컨테이너, 네임 스페이스 순서를 줄일 수 있습니다. 각각에는 하나 이상의 라우팅 테이블이 있지만 각각의 인스턴스 (VM / dockers / containers / namespaces)를 여러 개 가질 수 있으며 자유롭게 자유롭게 혼합 할 수 있습니다. 각 인스턴스는 Firefox와 같은 자체 응용 프로그램을 실행하여 행복하게 분리되었습니다. 다른 것들로부터.

아마도 해결 방법 중 하나에 여전히 관심이 있습니까?

편집하다:

가장 간단한 해결 방법은 네트워크 네임 스페이스입니다. 처리하는 NNS의 필요한 모든 측면 아래 스크립트는 (당신은 내가 일반적으로 사용하는, 당신의 이름을 선택 파일에 넣어 newns에서, 그러나 당신이 원하는 무엇이든 할) /usr/local/bin다음 chmod 755 FILE_NAME, 당신은 그것으로 다음 사용할 수 있습니다 :

       newns NAMESPACE_NAME start
       newns NAMESPACE_NAME stop

그것은 열립니다 xterm(작업에 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 "$@"

 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, ... 중 하나입니다 .-

하나의 경고를 추가해야합니다. 네임 스페이스 내부의 DNS 처리는 약간 버그가 있습니다. 인내심을 가지십시오.


1
그래서 나는 왜 내가 달성하려고하는 것이 쉽지도 않은지에 대한 매우 간단하면서도 자세한 설명을 얻었습니다! 감사합니다! 이것을 읽은 후에는 라우팅하려는 특정 프로그램의 트래픽 일 뿐이므로 항상 해당 프로그램을 라우팅하기를 원하기 때문에 해결 방법이 적절하다고 생각합니다. 예 : VideoGameA를 VPN을 통해 라우팅하고 싶지만 다른 프로그램을 통해 라우팅하고 싶지는 않습니다. VPN 인터페이스를 통해서만 특정 포트를 바인딩하는 간단한 방법이 있습니까? 그렇다면 어떻게 해당 인터페이스를 올바르게 설정하고 연결합니까?
Josh Raymond

@JoshRaymond Ok. 가장 간단한 해결 방법을 선택하려면 VPN에 라우팅 테이블을 게시하고 VideoGameA가 UDP 포트를 사용하는지 여부를 알려 주어야합니다.
MariusMatutiae 5

이 경로는 다음 표창에 게시됩니다 443, 3724 및 1119 TCP 및 UDP 포트를 모두 사용
조쉬 레이몬드에게

$ route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 0.0.0.0 0.0.0.0 U 50 0 0 ppp0 0.0.0.0 192.168.1.1 0.0.0.0 UG 100 0 0 enp10s0 1.0.0.1 0.0.0.0 255.255.255.255 UH 0 0 0 ppp0 192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 enp10s0 192.168.1.0 0.0.0.0 255.255.255.0 U 100 0 0 enp10s0 199.168.112.120 192.168.1.1 255.255.255.255 UGH 100 0 0 enp10s0
Josh Raymond

왜 @MariusMatutiae가 답과 다리를 만드는지 궁금합니다. veth 장치를 사용하는 것만으로도 잘 작동하는 것 같습니다.
Ian Kelling
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.