Leiten Sie nur bestimmten Datenverkehr über VPN weiter

11

Ich habe nach früheren Leuten gesucht, die ähnliche Fragen gestellt haben, aber noch keine klare Antwort erhalten, die für meine gegebene Situation geeignet ist.

Ich arbeite unter Linux (Fedora 22) und habe einen VPN-Dienst, für den ich bezahle. Ich benötige jedoch nur bestimmte Programme, um das VPN für den Internetverkehr zu verwenden, und kann meine Standard-ISP-Verbindung für alles andere verwenden (z. B. Surfen im Internet). usw)

Wir machen dies einfach und beschränken es auf das am häufigsten verwendete Programm, World of Warcraft, das über WINE ausgeführt wird.

Jetzt habe ich ein VPN-Setup über die Netzwerkschnittstelle, sodass der gesamte Datenverkehr über enp10s0 (der seltsame Name meines Computers für eth0) über den VPN-Dienst getunnelt werden kann. Ich benötige jedoch nur bestimmte Programme (oder Ports, die diese Programme verwenden) genau sein), um durch das VPN zu gehen.

Wie richte ich den Tunnel ein und lasse ihn nur die benötigten Ports über das VPN weiterleiten, während alles andere nicht geroutet wird?

Josh Raymond
quelle
Können Sie erklären, wie die anderen Antworten dieses Problem nicht lösen? Was ist einzigartig an Ihrem Setup?
Paul
1
Fast jeder von ihnen hat eine andere Art, dies zu erreichen, und keiner von ihnen macht es überhaupt einfach. Einige verwenden einen separaten Namespace für die Anwendung, andere verwenden eine Tunnelschnittstelle, andere tun dies direkt über openvpn in einem Terminal, aber keiner von ihnen, den ich gefunden habe, hat mir eine entschlüsselbare Methode gegeben, um eine dieser Methoden auszuführen.
Josh Raymond
Bitte sehen Sie meine Edit
MariusMatutiae

Antworten:

17

Was Sie verlangen, existiert nicht . Aus diesem Grund sind Sie mit den Antworten, die Sie gefunden haben, unzufrieden (einige davon sind möglicherweise meine): Alle haben Problemumgehungen vorgeschlagen , keine echte Lösung, weder einfach noch komplex.

Lassen Sie mich erklären. Das Routing in allen Betriebssystemen wird durch die Zieladresse bestimmt: Möglicherweise haben Sie mehrere Routen, aber die Wahl zwischen diesen basiert nicht auf der Anwendung, die die Verbindung aufruft, sondern lediglich auf der Zieladresse. Punkt.

Lassen Sie mich ein nicht triviales Beispiel geben. Wenn ein VPN-Client eine Verbindung zu seinem Server hergestellt hat, ist es weiterhin möglich, eine Verbindung zu einer bestimmten Site, z. B. example.org, außerhalb des VPN weiterzuleiten. Alle Anwendungen, die versuchen, diese spezielle Adresse zu erreichen, werden jedoch außerhalb des VPN weitergeleitet: Einige Anwendungen können nicht über das VPN zu example.org geleitet werden, während andere Apps außerhalb des VPN übertragen werden.

Mit dem Linux-Kernel, der das Quellrouting ermöglicht, wird die Situation reicher: Dies bedeutet, dass Sie zwei oder mehr Routingtabellen haben können und die Auswahl zwischen diesen auf der Quelladresse und nicht auf der Zieladresse basiert.

Ein nicht triviales Beispiel: Mein PC hat zwei Amtsleitungen mit zwei unterschiedlichen öffentlichen IPs. Es kann über beide Schnittstellen kontaktiert werden, und es ist wichtig, dass meine Antworten auf eine bestimmte Verbindung über dieselbe Schnittstelle erfolgen, über die die Verbindung hergestellt wurde. Andernfalls werden sie als irrelevant verworfen, wenn sie die Person erreichen, die die Verbindung hergestellt hat. Dies ist Quellrouting.

Fair genug, was ist mit Verbindungen, die wir beginnen? In einigen Apps können Sie die Bindungsadresse angeben, z. B. im openssh-Client :

-b bind_address

Verwenden Sie bind_address auf dem lokalen Computer als Quelladresse der Verbindung. Nur nützlich auf Systemen mit mehr als einer Adresse.

Für sie ist es kein Problem, wenn eine Instanz das VPN durchläuft (z. B. Routing-Tabelle 1), während eine andere Instanz das VPN verlässt (z. B. Routing-Tabelle 2). Andere Apps wie Firefox sind jedoch nicht nur notorisch schwer an eine bestimmte Quell-IP-Adresse zu binden (siehe hier für eine sehr clevere Problemumgehung), sondern auch gemein und böse, da Sie nicht zwei Kopien von sich selbst haben können läuft gleichzeitig und ist jeweils an eine andere Quelladresse gebunden. Mit anderen Worten, während Sie dank des oben genannten Tricks eine Instanz zur Bindung an eine Quelladresse Ihrer Wahl verpflichten können, können Sie keine andere Version davon an die andere Quelladresse binden lassen.

Dies erklärt, warum wir Problemumgehungen verwenden: Sie basieren alle auf der gleichen Idee, dass sie mit einem separaten Netzwerkstapel arbeiten als der Rest des PCs. Sie können also in abnehmender ungefährer Reihenfolge der Komplexität VMs, Docker, Container und Namespaces verwenden. In jeder von ihnen haben Sie eine oder mehrere Routing-Tabellen, aber Sie können mehrere Instanzen von jeder haben (VM / Docker / Container / Namespaces) und Sie können sie auch frei mischen, wobei jede von ihnen ihre eigene App wie Firefox ausführt, glücklich getrennt von den anderen.

Vielleicht interessieren Sie sich noch für eine der Problemumgehungen?

BEARBEITEN:

Die einfachste Lösung ist ein Netzwerk-Namespace. Das Skript unten Griffe alle notwendigen Aspekte eines NNS und legt es in einer Datei (Sie Ihren Namen wählen, verwende ich im Allgemeinen newns, aber Sie tun , was Sie bevorzugen) in /usr/local/bin, dann chmod 755 FILE_NAME, und Sie können es wie folgt verwendet werden :

       newns NAMESPACE_NAME start
       newns NAMESPACE_NAME stop

Es wird ein xtermfür Sie geöffnet (das liegt daran, dass xterm gerne funktioniert, aber Sie können es ändern, wenn Sie etwas anderes verwenden möchten), das zum neuen Namespace gehört. Wenn Sie möchten, können Sie aus dem xterm heraus Ihren VPN starten und dann Ihr Spiel starten. Mit dem folgenden Befehl können Sie leicht überprüfen, ob Sie das VPN verwenden:

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

Das gibt Ihnen Ihre öffentliche IP zurück. Nach dem Einrichten des VPN in xterm können Sie überprüfen, ob sich Ihre öffentliche IP in Ihren anderen Fenstern unterscheidet. Sie können bis zu 254 xterms mit 254 verschiedenen NNSs und verschiedenen Verbindungen öffnen.

#!/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

Wenn Sie möchten, können Sie mit sogar einen ganzen Desktop im neuen Netzwerk-Namespace starten

            sudo startx -- :2 

dann können Sie mit Alt+ Ctrl+ danach suchen Fn, wobei Fn einer von F1, F2, ....- ist

Ich muss eine Einschränkung hinzufügen: Die DNS-Behandlung in Namespaces ist etwas fehlerhaft, seien Sie geduldig.

MariusMatutiae
quelle
1
Und so habe ich endlich eine sehr einfache und doch detaillierte Erklärung, warum das, was ich erreichen will, weder einfach noch üblich ist! Vielen Dank! Nachdem ich dies gelesen habe, glaube ich, dass eine Problemumgehung angemessen wäre, da nur der Datenverkehr von einem bestimmten Programm weitergeleitet werden soll und ich immer möchte, dass dieses Programm weitergeleitet wird. Beispiel: Ich möchte, dass VideoGameA über das VPN weitergeleitet wird, aber ich möchte nicht, dass andere Programme über das VPN weitergeleitet werden. Gibt es eine einfache Möglichkeit, bestimmte Ports so zu binden, dass sie nur über die VPN-Schnittstelle übertragen werden? Wenn ja, wie würde ich diese Schnittstelle richtig einrichten und mit ihr verbinden?
Josh Raymond
@ JoshRaymond Ok. Um die einfachste Problemumgehung zu wählen, sollten Sie Ihre Routing-Tabelle mit dem VPN veröffentlichen und mir mitteilen, ob VideoGameA überhaupt UDP-Ports verwendet.
Marius Matutiae
Es verwendet sowohl die TCP- als auch die UDP-Ports 443, 3724 und 1119 Route wird im nächsten Lob veröffentlicht
Josh Raymond
$ 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
Ich frage mich, warum in der Antwort @MariusMatutiae einen Hahn und eine Brücke erstellt? Es scheint gut zu funktionieren, wenn man nur die veth-Geräte verwendet.
Ian Kelling