GNU/Linux >> Tutoriales Linux >  >> Linux

Enrutar solo tráfico específico a través de VPN

Lo que estás pidiendo no existir. Esta es la razón por la que no está satisfecho con las respuestas que encontró (algunas de ellas, posiblemente, sean mías):todas han sugerido soluciones alternativas , no una solución genuina, ni simple ni compleja.

Dejame explicar. El enrutamiento en todos los sistemas operativos está determinado por la dirección de destino:es muy posible que tenga varias rutas, pero la elección entre ellas no se basa en la aplicación que invoca la conexión, sino simplemente en la dirección de destino. Punto final.

Déjame darte un ejemplo no trivial. Cuando un cliente VPN ha establecido una conexión con su servidor, aún es posible enrutar una conexión a un sitio determinado, por ejemplo, example.org, fuera de la VPN. Pero todas las aplicaciones que intenten llegar a esa dirección especial se enrutarán fuera de la VPN:no puede hacer que algunas aplicaciones vayan a example.org a través de la VPN mientras que otras aplicaciones pasan fuera de la VPN.

La situación se enriquece con el kernel de Linux, que permite el enrutamiento de origen:esto significa que puede tener dos o más tablas de enrutamiento, y la elección entre ellas se basa en la dirección de origen, no en la dirección de destino.

Un ejemplo no trivial:mi PC tiene dos líneas externas, con dos direcciones IP públicas distintas. Se puede contactar a través de cualquiera de las interfaces, y es importante que mis respuestas a una conexión determinada pasen por la misma interfaz por la que entró la conexión:de lo contrario, se descartarán como irrelevantes cuando lleguen a la persona que inició la conexión. Este es el enrutamiento de origen.

Bastante justo, ¿qué pasa con las conexiones que empezamos? Algunas aplicaciones te permiten especificar la dirección de enlace, como el cliente openssh:

-b dirección_bind

Utilice bind_address en la máquina local como la dirección de origen de la conexión. Solo es útil en sistemas con más de una dirección.

Para ellos, no hay problema en que una instancia pase por la VPN (por ejemplo, la tabla de enrutamiento 1) mientras que otra instancia saldrá de la VPN (por ejemplo, la tabla de enrutamiento 2). Pero otras aplicaciones, como Firefox, no solo son notoriamente difíciles de vincular a una dirección IP de origen específica (pero vea aquí una solución alternativa muy inteligente), sino que también son malas y desagradables en el sentido de que no le permiten tener dos copias de sí mismos ejecutándose simultáneamente, cada uno vinculado a una dirección de origen diferente. En otras palabras, si bien gracias al truco mencionado anteriormente puede obligar a una instancia a vincularse a una dirección de origen de su elección, entonces no puede tener otra versión vinculada a la otra dirección de origen.

Esto explica por qué usamos soluciones alternativas:todas se basan en la misma idea, que funcionan con una pila de red separada que el resto de la PC. Por lo tanto, puede tener, en orden aproximado decreciente de complejidad, máquinas virtuales, acopladores, contenedores, espacios de nombres. En cada una de ellas tendrás una o más tablas de enrutamiento, pero puedes tener varias instancias de cada una (VM/dockers/containers/namespaces) y también puedes mezclarlas libremente, cada una de ellas ejecutando su propia aplicación como Firefox felizmente separadas de los otros.

¿Quizás todavía está interesado en una de las soluciones alternativas?

EDITAR:

La solución más sencilla es un espacio de nombres de red. El siguiente script maneja todos los aspectos necesarios de un NNS:colóquelo en un archivo (usted elige su nombre, generalmente uso newns , pero haz lo que prefieras) en /usr/local/bin , luego chmod 755 FILE_NAME , y puede usarlo de la siguiente manera:

       newns NAMESPACE_NAME start
       newns NAMESPACE_NAME stop

Se abrirá un xterm para ti (eso es porque me gusta que xterm funcione, pero puedes cambiarlo si deseas usar algo más), que pertenece al nuevo espacio de nombres. Desde dentro del xterm puede, si lo desea, iniciar su vpn y luego iniciar su juego. Puede verificar fácilmente que está utilizando la VPN a través del siguiente comando:

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

que te devuelve tu IP pública. Después de configurar la VPN en el xterm, puede verificar que su IP pública sea diferente en sus otras ventanas. Puede abrir hasta 254 xterms, con 254 NNS diferentes y conexiones diferentes.

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

Si lo desea, puede incluso iniciar un escritorio completo dentro del nuevo espacio de nombres de red, por medio de

            sudo startx -- :2 

entonces puedes buscarlo usando Alt +Ctrl +Fn , donde Fn es uno de F1,F2,....-

Necesito agregar una advertencia:el manejo de DNS dentro de los espacios de nombres es un poco defectuoso, sea paciente.


Linux
  1. Cómo permitir que solo usuarios no root específicos usen crontab

  2. Cómo obtener una dirección de memoria específica usando C

  3. Canalice solo STDERR a través de un filtro

  4. ¿Cómo puedo canalizar todo el tráfico de mi red a través de SSH?

  5. ¿Cómo enrutar solo una subred específica (ip de origen) a una interfaz en particular?

Abra puertos y enrute el tráfico a través de su firewall

Reenviar el tráfico http a otra dirección IP con iptables

Alimente todo el tráfico a través de OpenVPN solo para un espacio de nombres de red específico

Limite el acceso SSH a clientes específicos por dirección IP

¿Cómo ver en Linux qué interfaz de red y dirección IP de origen se utilizan para una ruta a un host de destino específico?

Encuentra la interfaz para la ruta a un host específico