Configure el enrutamiento e iptables para la nueva conexión VPN para redirigir ** solo ** los puertos 80 y 443

8

Tengo una nueva conexión VPN (usando openvpn) para permitirme enrutar algunas restricciones de ISP. Si bien funciona bien, está tomando todo el tráfico a través de la VPN. Esto me está causando problemas para descargar (mi conexión a Internet es mucho más rápida de lo que permite la VPN) y para el acceso remoto. Ejecuto un servidor ssh y tengo un demonio en ejecución que me permite programar descargas a través de mi teléfono.

Tengo mi conexión ethernet existente en eth0 y la nueva conexión VPN en tun0.

Creo que necesito configurar la ruta predeterminada para usar mi conexión eth0 existente en la red 192.168.0.0/24, y configurar la puerta de enlace predeterminada en 192.168.0.1 (mi conocimiento es inestable ya que no he hecho esto durante varios años ) Si eso es correcto, entonces no estoy exactamente seguro de cómo hacerlo. Mi tabla de enrutamiento actual es:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface    MSS   Window irtt
0.0.0.0         10.51.0.169     0.0.0.0         UG    0      0        0 tun0     0     0      0
10.51.0.1       10.51.0.169     255.255.255.255 UGH   0      0        0 tun0     0     0      0
10.51.0.169     0.0.0.0         255.255.255.255 UH    0      0        0 tun0     0     0      0
85.25.147.49    192.168.0.1     255.255.255.255 UGH   0      0        0 eth0     0     0      0
169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 eth0     0     0      0
192.168.0.0     0.0.0.0         255.255.255.0   U     1      0        0 eth0     0     0      0

Después de arreglar el enrutamiento, creo que necesito usar iptables para configurar el enrutamiento previo o el enmascaramiento para forzar todo para el puerto de destino 80 o 443 sobre tun0. De nuevo, ¡no estoy exactamente seguro de cómo hacer esto!

Todo lo que he encontrado en Internet está tratando de hacer algo mucho más complicado, y tratar de separar la madera de los árboles está resultando difícil.

Cualquier ayuda sería muy apreciada.

ACTUALIZAR

Hasta ahora, de varias fuentes, he improvisado lo siguiente:

#!/bin/sh

DEV1=eth0
IP1=`ifconfig|perl -nE'/dr:(\S+)/&&say$1'|grep 192.`
GW1=192.168.0.1
TABLE1=internet
TABLE2=vpn
DEV2=tun0
IP2=`ifconfig|perl -nE'/dr:(\S+)/&&say$1'|grep 10.`
GW2=`route -n | grep 'UG[ \t]' | awk '{print $2}'`

ip route flush table $TABLE1
ip route flush table $TABLE2
ip route show table main | grep -Ev ^default | while read ROUTE ; do
    ip route add table $TABLE1 $ROUTE
    ip route add table $TABLE2 $ROUTE
done
ip route add table $TABLE1 $GW1 dev $DEV1 src $IP1
ip route add table $TABLE2 $GW2 dev $DEV2 src $IP2
ip route add table $TABLE1 default via $GW1
ip route add table $TABLE2 default via $GW2

echo "1" > /proc/sys/net/ipv4/ip_forward
echo "1" > /proc/sys/net/ipv4/ip_dynaddr

ip rule add from $IP1 lookup $TABLE1
ip rule add from $IP2 lookup $TABLE2
ip rule add fwmark 1 lookup $TABLE1
ip rule add fwmark 2 lookup $TABLE2

iptables -t nat -A POSTROUTING -o $DEV1 -j SNAT --to-source $IP1
iptables -t nat -A POSTROUTING -o $DEV2 -j SNAT --to-source $IP2

iptables -t nat -A PREROUTING           -m state --state ESTABLISHED,RELATED          -j CONNMARK --restore-mark
iptables        -A OUTPUT               -m state --state ESTABLISHED,RELATED          -j CONNMARK --restore-mark
iptables -t nat -A PREROUTING -i $DEV1  -m state --state NEW                          -j CONNMARK --set-mark 1
iptables -t nat -A PREROUTING -i $DEV2  -m state --state NEW                          -j CONNMARK --set-mark 2
iptables -t nat -A PREROUTING           -m connmark --mark 1                          -j MARK --set-mark 1
iptables -t nat -A PREROUTING           -m connmark --mark 2                          -j MARK --set-mark 2
iptables -t nat -A PREROUTING           -m state --state NEW -m connmark ! --mark 0   -j CONNMARK --save-mark

iptables -t mangle -A PREROUTING -i $DEV2 -m state --state NEW -p tcp --dport  80 -j CONNMARK --set-mark 2
iptables -t mangle -A PREROUTING -i $DEV2 -m state --state NEW -p tcp --dport 443 -j CONNMARK --set-mark 2

route del default
route add default gw 192.168.0.1 eth0

Ahora esto parece estar funcionando. ¡Excepto que no lo es!

Las conexiones a los sitios web bloqueados están pasando, las conexiones que no están en los puertos 80 y 443 están usando la conexión que no es VPN.

Sin embargo, las conexiones de los puertos 80 y 443 que no están en los sitios web bloqueados también están utilizando la conexión no VPN.

Como se ha alcanzado el objetivo general, estoy relativamente contento, pero sería bueno saber por qué no funciona exactamente bien.

¿Algunas ideas?

Como referencia, ahora tengo 3 tablas de enrutamiento, principal, internet y vpn. La lista de ellos es la siguiente ...

Principal:

default via 192.168.0.1 dev eth0 
10.38.0.1 via 10.38.0.205 dev tun0 
10.38.0.205 dev tun0  proto kernel  scope link  src 10.38.0.206 
85.removed via 192.168.0.1 dev eth0 
169.254.0.0/16 dev eth0  scope link  metric 1000 
192.168.0.0/24 dev eth0  proto kernel  scope link  src 192.168.0.73  metric 1 

Internet:

default via 192.168.0.1 dev eth0 
10.38.0.1 via 10.38.0.205 dev tun0 
10.38.0.205 dev tun0  proto kernel  scope link  src 10.38.0.206 
85.removed via 192.168.0.1 dev eth0 
169.254.0.0/16 dev eth0  scope link  metric 1000 
192.168.0.0/24 dev eth0  proto kernel  scope link  src 192.168.0.73  metric 1 
192.168.0.1 dev eth0  scope link  src 192.168.0.73

VPN:

default via 10.38.0.205 dev tun0 
10.38.0.1 via 10.38.0.205 dev tun0 
10.38.0.205 dev tun0  proto kernel  scope link  src 10.38.0.206 
85.removed via 192.168.0.1 dev eth0 
169.254.0.0/16 dev eth0  scope link  metric 1000 
192.168.0.0/24 dev eth0  proto kernel  scope link  src 192.168.0.73  metric 1
Steve
fuente
El script anterior funciona como se esperaba. Solo esperaba ver el tráfico procedente de la 10. dirección en netstat. Sin embargo, todo el tráfico se origina en 192., pero los puertos 80 y 443 se dirigen a través de VPN. Pondré toda la solución en una respuesta, pero apoya a @anttir por sugerir iproute2 y fwmark. ¡No los había encontrado, y sin ellos todavía estaría golpeándome la cabeza contra una pared de ladrillos!
Steve

Respuestas:

4

Entonces, la mayor parte de esto está arriba, pero la solución completa fue la siguiente:

Edite / etc / iproute2 / rt_tables y agregue 2 líneas en la parte inferior:

101 internet
102 vpn

Puede dar a estas tablas otros nombres que tengan más sentido, solo sea coherente.

Entonces necesita crear un script (lo llamé rt_setup) en /etc/init.d

#!/bin/sh

DEV1=eth0
IP1=`ifconfig|perl -nE'/dr:(\S+)/&&say$1'|grep 192.`
GW1=192.168.0.1
TABLE1=internet
TABLE2=vpn
DEV2=tun0
IP2=`ifconfig|perl -nE'/dr:(\S+)/&&say$1'|grep 10.`
GW2=`route -n | grep 'UG[ \t]' | awk '{print $2}'`

ip route flush table $TABLE1
ip route flush table $TABLE2
ip route show table main | grep -Ev ^default | while read ROUTE ; do
    ip route add table $TABLE1 $ROUTE
    ip route add table $TABLE2 $ROUTE
done
ip route add table $TABLE1 $GW1 dev $DEV1 src $IP1
ip route add table $TABLE2 $GW2 dev $DEV2 src $IP2
ip route add table $TABLE1 default via $GW1
ip route add table $TABLE2 default via $GW2

echo "1" > /proc/sys/net/ipv4/ip_forward
echo "1" > /proc/sys/net/ipv4/ip_dynaddr

ip rule add from $IP1 lookup $TABLE1
ip rule add from $IP2 lookup $TABLE2
ip rule add fwmark 1 lookup $TABLE1
ip rule add fwmark 2 lookup $TABLE2

iptables -t nat -A POSTROUTING -o $DEV1 -j SNAT --to-source $IP1
iptables -t nat -A POSTROUTING -o $DEV2 -j SNAT --to-source $IP2

iptables -t nat -A PREROUTING           -m state --state ESTABLISHED,RELATED          -j CONNMARK --restore-mark
iptables        -A OUTPUT               -m state --state ESTABLISHED,RELATED          -j CONNMARK --restore-mark
iptables -t nat -A PREROUTING -i $DEV1  -m state --state NEW                          -j CONNMARK --set-mark 1
iptables -t nat -A PREROUTING -i $DEV2  -m state --state NEW                          -j CONNMARK --set-mark 2
iptables -t nat -A PREROUTING           -m connmark --mark 1                          -j MARK --set-mark 1
iptables -t nat -A PREROUTING           -m connmark --mark 2                          -j MARK --set-mark 2
iptables -t nat -A PREROUTING           -m state --state NEW -m connmark ! --mark 0   -j CONNMARK --save-mark

iptables -t mangle -A PREROUTING -i $DEV2 -m state --state NEW -p tcp --dport  80 -j CONNMARK --set-mark 2
iptables -t mangle -A PREROUTING -i $DEV2 -m state --state NEW -p tcp --dport 443 -j CONNMARK --set-mark 2

route del default
route add default gw 192.168.0.1 eth0

Luego, obviamente, vincúlelo desde /etc/rc2.d (uso ubuntu, el nivel de ejecución puede ser diferente para usted). ¡Asegúrate de darle un número S más alto que el enlace openvpn!

El guión hace varias cosas. La parte superior configura las variables, con algunas instrucciones perl y awk utilizadas para recoger las direcciones IP y direcciones de puerta de enlace dinámicas. La segunda sección limpia las tablas que configuró en ipruote2 y les copia la tabla de enrutamiento actual. Luego crea dos rutas nuevas y dos puertas de enlace predeterminadas para ellos, con la VPN que pasa por la VPN y la de Internet que pasa por mi red local.

No estoy convencido de que las siguientes 2 líneas sean necesarias, pero permiten el reenvío de IP para su uso en iptables.

A continuación, el script crea algunas reglas sobre dónde buscar el tráfico que se origina en la dirección IP relevante y dónde buscar si el tráfico está marcado específicamente.

¡La POSTROUTING y PREROUTING aseguran que el tráfico que se origina en una dirección recibe la respuesta!

La versión final de iptables PREROUTING es la parte que etiqueta el tráfico y garantiza que todo lo que vaya a los puertos 80 o 443 esté marcado para usar la Tabla 2 (VPN)

Las dos líneas finales eliminan la puerta de enlace VPN de la tabla de enrutamiento predeterminada y agregan nuevamente mi puerta de enlace de red local.

Tal como está, el proceso funciona de manera brillante. La VPN se inicia cuando aparece la máquina, y este script se ejecuta unos segundos más tarde (puedo agregar una declaración de suspensión solo para asegurarme de que la VPN esté completamente inicializada antes de ejecutar este script). Mi conexión de acceso remoto (ssh, etc.) funciona muy bien. ¡Mis conexiones que no van a los puertos 80 o 443 están usando mi conexión local, pero todo el tráfico web va a través de la VPN y omite los controles establecidos por mi ISP!

Como dije en mi comentario bajo mi pregunta, ni siquiera habría comenzado a mirar esta ruta sin la sugerencia de @anttir. Detrás de esa sugerencia, los sitios http://blog.khax.net/2009/11/28/multi-gateway-routing-with-iptables-and-iproute2/ y http://linux-ip.net/ html / adv-multi-internet.html ha sido muy útil (¡incluso si el código no está 100% completo!)

Steve
fuente
1
Una última adición, agregué un sleep 20a la parte superior del script ya que la conexión openvpn no se completaba a tiempo. También agregué echo 2 > /proc/sys/net/ipv4/conf/tun0/rp_filteral script ya que es necesario deshabilitar el filtro de paquetes inverso para tun0. Cuando vuelve una respuesta de tun0 con la dirección de origen S, el filtro de paquetes inverso comprueba "si tuviera que enrutar un paquete a la dirección S, y no pasaría por tun0, dejaré caer el paquete", y porque al hacer esto Si no hay una marca fw válida, determina que la ruta sería la ruta predeterminada habitual, por lo que descarta el paquete.
Steve
Tuve que editar tu script para que funcione para mí. La última línea route add default gw 192.168.0.1 eth0parecía enrutar el tráfico del puerto 80/443 a través de la puerta de enlace local en lugar del tun0 como estaba previsto. Cambiar la última línea route add default tun0parece hacer el truco para mí.
1

El enrutamiento por protocolo es un poco complicado. Por lo general, la tabla de enrutamiento se usa para verificar la puerta de enlace de acuerdo con la IP de destino y usar la puerta de enlace predeterminada openvpn o 192.168.0.1.

Sería más fácil configurar, por ejemplo, el proxy http Squid en el otro extremo de la VPN y configurar el navegador para usar el proxy.

No usaría las iptables ya que cambiaría la IP de destino de la conexión HTTP y no funcionaría.

Puede crear una nueva tabla de enrutamiento (/ etc / iproute2 / rt_tables) con la ruta predeterminada establecida en el punto final VPN, usar iptables fwmark (-j MARK) para marcar todos los paquetes HTTP y luego usar la regla ip para crear una regla personalizada para el paquetes marcados para usar la nueva tabla de enrutamiento.

Antti Rytsölä
fuente
Gracias por tu ayuda. Ciertamente voy a echar un vistazo a esos. Las cosas son un poco complicadas porque no tengo control del servidor, solo de mi lado. Además, no puedo usar squid porque necesito enrutar el tráfico https a través de la conexión, y squid no funciona tan bien con eso.
Steve
¿Qué tal enrutar solo unas pocas IP sobre la VPN y el resto del mundo fuera de la VPN?
Antti Rytsölä
Pensé en enrutar solo algunas IP, pero la lista cambia a medida que los sitios se mueven, y necesito que sea fácil de usar para otros usuarios en la PC. He comenzado a buscar la creación de una nueva tabla de enrutamiento y marcar los paquetes. Los paquetes de marcado fueron fáciles, son las tablas de enrutamiento de las que no estoy tan seguro. Puedo configurar uno para VPN que se vea bien, y uno para todo lo demás que se vea bien, pero no estoy seguro de qué hacer con main, ya que todavía está configurado en los valores predeterminados (que es VPN). Sigo jugando ...
Steve
linux-ip.net/html/adv-multi-internet.html ip rule show y ip rule add fwmark 4 tabla 4 prioridad 10000
Antti Rytsölä
¡Se agregó una actualización al original que detalla dónde estoy hasta ahora! AH! Me acabo de dar cuenta de que he editado tu respuesta, no mi pregunta. ¡Lo siento! ¡No he usado tanto, y no me di cuenta de que podía editar la respuesta de otra persona!
Steve