Instradare solo traffico specifico tramite VPN


11

Ho cercato persone precedenti che facevano domande simili, ma devo ancora ottenere una risposta diretta che funzionerà per la mia situazione, quindi ecco qui ..

Sono in esecuzione su Linux (Fedora 22) e ho un servizio VPN per il quale pago, tuttavia ho solo bisogno di programmi specifici per utilizzare la VPN per il loro traffico Internet e posso usare la mia connessione ISP standard per tutto il resto (ad esempio, navigazione web, eccetera)

Lo renderemo semplice e lo limiteremo al programma più usato, World of Warcraft, che viene eseguito su WINE.

Ora, ho una configurazione VPN tramite l'interfaccia di rete in modo che tutto il mio traffico attraverso enp10s0 (nome strano dei miei computer per eth0) possa essere trasferito attraverso il servizio VPN, tuttavia, ho solo bisogno di programmi specifici (o porte che quei programmi usano, per sii specifico) per passare attraverso la VPN.

Come posso configurare il tunnel e instradare solo le porte necessarie attraverso la VPN, mantenendo tutto il resto non instradato?


Puoi spiegare come le altre risposte non affrontano questo problema? Cosa rende unico il tuo setup?
Paul,

1
Quasi tutti hanno un modo diverso di realizzarlo, e nessuno di loro lo rende affatto semplice. Alcuni usano uno spazio dei nomi separato per l'applicazione, altri usano un'interfaccia tunnel, altri lo fanno direttamente attraverso openvpn in un terminale, ma nessuno di quelli che ho trovato mi ha dato un metodo decifrabile per fare uno di questi.
Josh Raymond,

Si prega di vedere il mio Edit
MariusMatutiae l'

Risposte:


17

Quello che stai chiedendo non esiste. Questo è il motivo per cui non sei soddisfatto delle risposte che hai trovato (alcune di esse, forse, sono mie): tutte hanno suggerito soluzioni alternative , non una soluzione autentica, semplice o complessa.

Lasciatemi spiegare. Il routing in tutti i sistemi operativi è determinato dall'indirizzo di destinazione: potresti benissimo avere diversi percorsi, ma la scelta tra di essi non si basa sull'applicazione che richiama la connessione, ma semplicemente sull'indirizzo di destinazione. Punto.

Lascia che ti faccia un esempio non banale. Quando un client VPN ha stabilito una connessione al suo server, è ancora possibile instradare una connessione a un determinato sito, ad esempio esempio.org, al di fuori della VPN. Ma tutte le applicazioni che tentano di raggiungere quell'indirizzo speciale verranno instradate al di fuori della VPN: non è possibile avere alcune applicazioni che vanno a example.org tramite la VPN mentre altre app passano al di fuori della VPN.

La situazione diventa più ricca con il kernel Linux, che consente il routing dei sorgenti: questo significa che puoi avere due o più tabelle di routing, e la scelta tra loro si basa sull'indirizzo di origine, non su quello di destinazione.

Un esempio non banale: il mio pc ha due linee esterne, con due IP pubblici distinti. Può essere contattato tramite entrambe le interfacce ed è importante che le mie risposte a una determinata connessione passino attraverso la stessa interfaccia in cui è avvenuta la connessione: altrimenti verranno scartate come irrilevanti quando raggiungono la persona che ha avviato la connessione. Questo è il routing di origine.

Abbastanza giusto, che dire delle connessioni che iniziamo? Alcune app consentono di specificare l'indirizzo di bind, come il client openssh :

-b indirizzo_bind

Utilizzare bind_address sul computer locale come indirizzo di origine della connessione. Utile solo su sistemi con più di un indirizzo.

Per loro, non c'è nessun problema ad avere un'istanza che passa attraverso la VPN (diciamo, tabella di routing 1) mentre un'altra istanza andrà fuori dalla VPN (diciamo tabella di routing 2). Ma altre app, come Firefox, non solo sono notoriamente difficili da associare a un indirizzo IP sorgente specifico (ma vedi qui per una soluzione molto intelligente), ma sono anche cattive e cattive in quanto non ti permetteranno di avere due copie di se stesse in esecuzione contemporaneamente, ciascuno associato a un indirizzo di origine diverso. In altre parole, mentre grazie al trucco di cui sopra puoi obbligare un'istanza a collegarsi a un indirizzo sorgente di tua scelta, non puoi avere un'altra versione di esso vincolante per l'altro indirizzo sorgente.

Questo spiega perché usiamo soluzioni alternative: sono tutti basati sulla stessa idea, che funzionano con uno stack di rete separato rispetto al resto del PC. Quindi puoi avere, in ordine decrescente di complessità, VM, docker, container, spazi dei nomi. In ognuna di esse avrai una o più tabelle di routing, ma puoi avere diverse istanze di ciascuna (VM / docker / contenitori / spazi dei nomi) e puoi anche mescolarle liberamente, ognuna delle quali esegue la propria app come Firefox felicemente separata dagli altri.

Forse sei ancora interessato a una delle soluzioni alternative?

MODIFICARE:

La soluzione più semplice è uno spazio dei nomi di rete. Lo script di seguito gestisce tutti gli aspetti necessari di un NNS: inseriscilo in un file (scegli il tuo nome, generalmente lo uso newns, ma fai quello che preferisci) in /usr/local/bin, quindi chmod 755 FILE_NAME, e puoi usarlo come segue:

       newns NAMESPACE_NAME start
       newns NAMESPACE_NAME stop

xtermTi aprirà un (perché mi piace che xterm funzioni, ma puoi cambiarlo se desideri usare qualcos'altro), che appartiene al nuovo spazio dei nomi. Dall'interno di xterm puoi, se lo desideri, avviare la tua VPN, quindi iniziare il gioco. Puoi facilmente verificare che stai utilizzando la VPN tramite il seguente comando:

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

che ti restituisce il tuo IP pubblico. Dopo aver impostato la VPN in xterm, puoi verificare che il tuo IP pubblico sia diverso nelle altre finestre. È possibile aprire fino a 254 xterm, con 254 NNS diversi e connessioni diverse.

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

Se lo desideri, puoi anche avviare un intero desktop all'interno del nuovo spazio dei nomi di rete, tramite

            sudo startx -- :2 

allora puoi cercarlo usando Alt+ Ctrl+ Fn, dove Fn è uno di F1, F2, ....-

Devo aggiungere un avvertimento: la gestione del DNS all'interno degli spazi dei nomi è un po 'buggy, abbi pazienza.


1
E così ho finalmente una spiegazione molto semplice ma dettagliata del perché ciò che sto cercando di realizzare non è né facile né comune! Grazie! Dopo aver letto questo, credo che una soluzione alternativa sarebbe appropriata, poiché è solo il traffico proveniente da un programma specifico che voglio instradare e vorrei sempre che quel programma fosse indirizzato. Esempio: voglio che VideoGameA venga instradato attraverso la VPN, ma non voglio che altri programmi vengano instradati attraverso di essa. Esiste un modo semplice per associare porte specifiche per passare solo attraverso l'interfaccia VPN? In tal caso, come dovrei configurare e connettermi correttamente a detta interfaccia?
Josh Raymond,

@JoshRaymond Ok. Al fine di scegliere la soluzione più semplice, è necessario fornire la tabella di routing post con la VPN e dirmi se VideoGameA utilizza le porte UDP.
MariusMatutiae,

Utilizza entrambe le porte TCP e UDP 443, 3724 e 1119 Route verrà pubblicata nel prossimo encomio
Josh Raymond l'

$ 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,

Mi chiedo perché nella risposta @MariusMatutiae crea un rubinetto e un ponte? Sembra funzionare bene solo usando i dispositivi veth.
Ian Kelling il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.