Puede iniciar el enlace OpenVPN dentro de un espacio de nombres y luego ejecutar todos los comandos que desee para usar ese enlace OpenVPN dentro del espacio de nombres. Los detalles sobre cómo hacerlo se presentan en Ejecución de un túnel OpenVPN dentro de un espacio de nombres de red, por Sebastian Thorarensen.
Lo probé y funciona. La idea es proporcionar un script personalizado para llevar a cabo las fases de activación y enrutamiento de la conexión OpenVPN dentro de un espacio de nombres específico en lugar del global. Aquí hay una respuesta basada en la fuente anterior, pero modificada para agregar Google DNS a resolv.conf
.
Primero crea un --up secuencia de comandos para OpenVPN. Este script creará la interfaz del túnel VPN dentro de un espacio de nombres de red llamado vpn , en lugar del espacio de nombres predeterminado.
$ cat > netns-up << 'EOF'
#!/bin/sh
case $script_type in
up)
ip netns add vpn
ip netns exec vpn ip link set dev lo up
mkdir -p /etc/netns/vpn
echo "nameserver 8.8.8.8" > /etc/netns/vpn/resolv.conf
ip link set dev "$1" up netns vpn mtu "$2"
ip netns exec vpn ip addr add dev "$1" \
"$4/${ifconfig_netmask:-30}" \
${ifconfig_broadcast:+broadcast "$ifconfig_broadcast"}
test -n "$ifconfig_ipv6_local" && \
ip netns exec vpn ip addr add dev "$1" \
"$ifconfig_ipv6_local"/112
;;
route-up)
ip netns exec vpn ip route add default via "$route_vpn_gateway"
test -n "$ifconfig_ipv6_remote" && \
ip netns exec vpn ip route add default via \
"$ifconfig_ipv6_remote"
;;
down)
ip netns delete vpn
;;
esac
EOF
Luego inicie OpenVPN y dígale que use nuestro --up script en lugar de ejecutar ifconfig y route.
openvpn --ifconfig-noexec --route-noexec --up netns-up --route-up netns-up --down netns-up
Ahora puede iniciar programas para ser tunelizados así:
ip netns exec vpn command
El único inconveniente es que debe ser root para invocar ip netns exec ...
y tal vez no quiera que su aplicación se ejecute como root. La solución es simple:
sudo ip netns exec vpn sudo -u $(whoami) command
Resulta que puedes poner una interfaz de túnel en un espacio de nombres de red. Todo mi problema se debió a un error al abrir la interfaz:
ip addr add dev $tun_tundv \
local $ifconfig_local/$ifconfig_cidr \
broadcast $ifconfig_broadcast \
scope link
El problema es el "enlace de alcance", que entendí mal porque solo afectaba el enrutamiento. Hace que el kernel establezca la dirección de origen de todos los paquetes enviados al túnel en 0.0.0.0
; presumiblemente, el servidor OpenVPN los descartaría como no válidos según RFC1122; incluso si no fuera así, el destino obviamente no podría responder.
Todo funcionó correctamente en ausencia de espacios de nombres de red porque el script de configuración de red incorporado de openvpn no cometió este error. Y sin "enlace de alcance", mi script original también funciona.
(¿Cómo descubrí esto, te preguntarás? Al ejecutar strace
en el proceso de openvpn, establezca el volcado hexadecimal de todo lo que lea del descriptor del túnel y luego decodifique manualmente los encabezados de los paquetes).
El error al intentar crear los dispositivos veth se debe a un cambio en la forma en que ip
interpreta los argumentos de la línea de comandos.
La invocación correcta de ip
crear un par de dispositivos veth es
ip link add name veth0 type veth peer name veth1
(name
instancia de dev
)
Ahora, ¿cómo sacar el tráfico del espacio de nombres al túnel VPN? Dado que solo tiene dispositivos sintonizados a su disposición, el "anfitrión" debe enrutar. Es decir. cree el par veth y coloque uno en el espacio de nombres. Conecte el otro a través de enrutamiento al túnel. Por lo tanto, habilite el reenvío y luego agregue las rutas necesarias.
Por ejemplo, suponga que eth0
es tu interfaz principal, tun0
es su interfaz de túnel VPN y veth0
/veth1
el par de interfaces de las cuales veth1
está en el espacio de nombres. Dentro del espacio de nombres, agrega solo una ruta predeterminada para veth1
.
En el host, debe emplear el enrutamiento de políticas, consulte aquí, por ejemplo. Lo que tienes que hacer:
Añadir/añadir una entrada como
1 vpn
a /etc/iproute2/rt_tables
. Con esto puede llamar a la tabla (aún por crear) por su nombre.
Luego use las siguientes declaraciones:
ip rule add iif veth0 priority 1000 table vpn
ip rule add iif tun0 priority 1001 table vpn
ip route add default via <ip-addr-of-tun0> table vpn
ip route add <ns-network> via <ip-addr-of-veth0> table vpn
No puedo probar eso aquí con una configuración como la tuya, pero esto debería hacer exactamente lo que quieres. Puede aumentar eso mediante reglas de filtrado de paquetes de modo que ni la vpn ni la red de "invitados" se vean perturbadas.
nótese bien Moviendo tun0
en el espacio de nombres en primer lugar parece lo correcto. Pero como tú, no conseguí que eso funcionara. El enrutamiento de políticas parece ser el siguiente paso correcto. La solución de Mahendra es aplicable si conoce las redes detrás de la VPN y todas las demás aplicaciones nunca accederán a esas redes. Pero su condición inicial ("todo el tráfico y solo el tráfico, hacia/desde procesos específicos pasa a través de la VPN") suena como si esto último no pudiera garantizarse.