GNU/Linux >> Znalost Linux >  >> Linux

Směrujte pouze konkrétní provoz přes VPN

To, o co žádáte, není existovat. To je důvod, proč jste nespokojeni s odpověďmi, které jste našli (některé z nich jsou možná moje):všichni navrhli řešení , nejde o skutečné řešení, ať už jednoduché, ani složité.

Nech mě to vysvětlit. Směrování ve všech operačních systémech je určeno cílovou adresou:velmi dobře můžete mít několik cest, ale výběr mezi nimi není založen na aplikaci vyvolávající připojení, ale jednoduše na cílové adrese. Tečka.

Dovolte mi uvést netriviální příklad. Když klient VPN naváže připojení ke svému serveru, je stále možné směrovat připojení k danému webu, řekněme example.org, mimo VPN. Ale všechny aplikace, které se pokoušejí dosáhnout této speciální adresy, budou směrovány mimo VPN:nemůžete nechat některé aplikace přejít na example.org přes VPN, zatímco jiné aplikace projdou mimo VPN.

S linuxovým jádrem, které umožňuje zdrojové směrování, je situace ještě bohatší:to znamená, že můžete mít dvě nebo více směrovacích tabulek a výběr mezi nimi je založen na zdrojové adrese, nikoli na cílové adrese.

Netriviální příklad:můj počítač má dvě vnější linky se dvěma odlišnými veřejnými IP. Lze jej kontaktovat přes kterékoli rozhraní a je důležité, aby mé odpovědi na dané připojení procházely přes stejné rozhraní, přes které připojení přišlo:jinak budou vyřazeny jako irelevantní, když se dostanou k osobě, která připojení iniciovala. Toto je směrování zdroje.

Spravedlivé, co spojení, která začínáme? Některé aplikace umožňují zadat adresu vazby, například klient openssh:

-b adresa_vazby

Použijte bind_address na lokálním počítači jako zdrojovou adresu připojení. Užitečné pouze v systémech s více než jednou adresou.

Pro ně není žádný problém, když jedna instance projde VPN (řekněme směrovací tabulka 1), zatímco jiná instance půjde mimo VPN (řekněme směrovací tabulka 2). Ale jiné aplikace, jako je Firefox, nejenže je notoricky obtížné svázat se s konkrétní zdrojovou IP adresou (viz zde ale velmi chytré řešení), ale jsou také zlé a odporné v tom, že nebudou umožňují mít dvě jejich kopie spuštěné současně, přičemž každá je vázána na jinou zdrojovou adresu. Jinými slovy, zatímco díky výše uvedenému triku můžete zavázat jednu instanci k tomu, aby se navázala na zdrojovou adresu dle vašeho výběru, nemůžete mít jinou její verzi navázanou na druhou zdrojovou adresu.

To vysvětluje, proč používáme náhradní řešení:všechny jsou založeny na stejné myšlence, že pracují se samostatným síťovým zásobníkem než zbytek počítače. Takže můžete mít virtuální počítače, dockery, kontejnery, jmenné prostory, v klesajícím přibližném pořadí složitosti. V každé z nich budete mít jednu nebo více směrovacích tabulek, ale můžete mít několik instancí každé (VM/dockery/kontejnery/jmenné prostory) a můžete je také volně míchat, každá z nich běží svou vlastní aplikaci, jako je Firefox, šťastně oddělená od ostatních.

Možná vás stále zajímá jedno z řešení?

UPRAVIT:

Nejjednodušším řešením je síťový jmenný prostor. Skript níže zpracovává všechny potřebné aspekty NNS:vložte jej do souboru (vyberete si své jméno, já obecně používám newns , ale můžete dělat, co chcete) v /usr/local/bin a poté chmod 755 FILE_NAME a můžete jej použít následovně:

       newns NAMESPACE_NAME start
       newns NAMESPACE_NAME stop

Otevře se xterm pro vás (to proto, že se mi líbí, že xterm funguje, ale můžete to změnit, pokud chcete použít něco jiného), který patří do nového jmenného prostoru. Pokud si přejete, můžete zevnitř xtermu spustit vpn a poté spustit hru. Pomocí následujícího příkazu můžete snadno zkontrolovat, zda používáte VPN:

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

který vám vrátí vaši veřejnou IP. Po nastavení VPN v xterm můžete zkontrolovat, zda se vaše veřejná IP liší ve vašich ostatních oknech. Můžete otevřít až 254 xtermů s 254 různými NNS a různými připojeními.

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

Pokud chcete, můžete dokonce spustit celou plochu v novém síťovém jmenném prostoru pomocí

            sudo startx -- :2 

pak jej můžete vyhledat pomocí Alt +Ctrl +Fn , kde Fn je jedno z F1, F2,....-

Potřebuji přidat jedno upozornění:zpracování DNS uvnitř jmenných prostorů je trochu chybné, buďte trpěliví.


Linux
  1. Ssh – tunelový provoz přes jiný stroj přes Ssh?

  2. Jak povolit pouze konkrétním uživatelům bez oprávnění root používat crontab

  3. Monitorujte provoz TCP na konkrétním portu

  1. Přístup pouze pro čtení ke všem souborům v konkrétní podsložce?

  2. Přidáním trasy ke konkrétnímu hostiteli získáte určité rozhraní

  3. Proč síťový provoz Linuxu prochází pouze přes eth0?

  1. Jak zajistit, aby veškerý internetový provoz procházel pouze přes VPN?

  2. Jak získat konkrétní adresu paměti pomocí C

  3. Přes filtr veďte pouze STDERR