Tres equipos Linux, un diseño: un concentrador OpenVPN accesible públicamente, un portátil de consumidor y una máquina de salida detrás de un router doméstico corriente que no reenvía nada hacia dentro. La salida marca el concentrador por sí misma. El tráfico de internet del consumidor entra entonces en el túnel en el portátil y sale por el enlace ascendente propio de la salida. Todo lo sorprendente de esta disposición se deduce de un detalle: la salida inició la conexión, así que el camino hacia dentro ya existe y no hace falta ninguna redirección de puerto para crearlo.

Lo que sigue recorre el camino del paquete y no el orden de la configuración, porque la configuración solo tiene sentido cuando sabes qué componente toma qué decisión. Cada capa toma exactamente una decisión, y los errores se agrupan donde se dan dos capas por una.

Dos sesiones de transporte, un camino interior

Cada equipo mantiene su propia conexión exterior al concentrador, y ninguna de esas conexiones sabe de la otra. El tráfico del consumidor hacia internet es un flujo interior aparte que se transporta dentro del túnel del consumidor y luego se emite de nuevo desde el túnel de la salida. Ese flujo interior es lo que el concentrador tiene que enrutar y lo que la salida tiene que reenviar.

outer: consumer --TLS--> hub
outer: exit     --TLS--> hub
inner: consumer --tun--> hub --internal--> exit --tun--> uplink

Como ambas conexiones exteriores salen del lado del cliente, el router de la salida nunca ve un SYN entrante ni necesita nunca una regla de NAT de destino. Solo tiene que mantener vivo el transporte establecido, cosa que ya hace para cualquier conexión duradera. Nada en la internet pública necesita llegar primero a la salida, por eso una dirección dinámica en ese enlace ascendente no es un problema. El router sigue teniendo que permitir la sesión saliente, pero es el mismo permiso que ya usa un navegador.

Qué instala realmente iroute dentro del servidor

El concentrador es el único dispositivo que decide qué par posee qué destino, y lo hace en su propia tabla de enrutamiento de espacio de usuario, no en la del núcleo. Una entrada client-config-dir para la salida llamada exit-node puede reclamar allí el prefijo por defecto:

# /etc/openvpn/server/ccd/exit-node
iroute 0.0.0.0 0.0.0.0

Esa línea le dice al proceso del servidor "los paquetes interiores con cualquier destino pertenecen a este cliente". No añade una ruta por defecto al sistema operativo del concentrador ni convierte al concentrador en una puerta de enlace de internet. Referencia de OpenVPN 2.6 mantiene el enrutamiento interno específico del cliente y el enrutamiento del núcleo como mecanismos separados, y esa separación es la razón por la que el diseño funciona sin tocar la ruta por defecto del concentrador.

El consumidor necesita la instrucción espejo, entregada como push, para que su propio tráfico entre en el túnel en lugar de salir por su puerta de enlace local. Con topología de subred, el conjunto es una ruta conectada en el dispositivo tun de la salida, así que la dirección de vuelta no necesita ningún push adicional; lo que la salida no debe recibir es la redirección de abajo, que devolvería su propio tráfico ascendente al túnel que intenta usar. Envíala solo al consumidor y lee las rutas aplicadas en el cliente en lugar de confiar en que se eligió el archivo CCD.

# /etc/openvpn/server/ccd/consumer-01
push "redirect-gateway def1"

El núcleo de la salida hace el reenvío

Dentro de la salida, un paquete del consumidor llega a la interfaz tun dirigido a algún equipo de internet. El núcleo consulta su tabla de enrutamiento, encuentra el enlace ascendente real como la mejor coincidencia y luego aplica dos políticas independientes: si el paquete puede reenviarse y si puede salir por esa interfaz con esa dirección de origen. El reenvío es un sysctl y viene desactivado por defecto en muchas distribuciones.

Así que la salida necesita el reenvío IPv4 activado de forma persistente, una regla que admita los orígenes del túnel del consumidor hacia el enlace ascendente y el camino de respuesta de vuelta por el tun. Activar el reenvío para todo el equipo también cambia el comportamiento de cualquier otra cosa que enrute a través de él, por eso la regla debería nombrar los orígenes e interfaces en lugar de aceptarlo todo.

La traducción de origen es lo que compra el camino de vuelta

Un equipo de internet no tiene ruta hacia una dirección 10.90.0.x, así que las respuestas se descartarían antes de llegar a la salida. Reescribir el origen mientras el paquete sale por el enlace ascendente lo resuelve, y el seguimiento de conexiones deshace la reescritura a la vuelta.

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 10.90.0.0/24 -o enp1s0 -j MASQUERADE
ip -4 route get 10.90.0.9   # run on the exit: must point at the tun

La regla de arriba es un punto de partida para una interfaz ascendente, no una política de cortafuegos. Estrecha el origen a las asignaciones que realmente autorizaste y mantén la política de entrada propia de la salida separada, para que el enmascaramiento del tráfico del túnel no exponga en silencio servicios locales. En un equipo con dirección ascendente dinámica, el enmascaramiento también te ahorra seguir la dirección a mano.

Dónde puede el concentrador imponer normas y dónde no

Con client-to-client y el camino de datos tradicional de espacio de usuario, el concentrador entrega paquetes interiores entre pares dentro del proceso del servidor. Nunca atraviesan la cadena FORWARD del núcleo del concentrador, así que una regla del núcleo allí no puede restringir el tránsito entre pares, por cuidadosamente escrita que esté. La imposición tiene que vivir en la política propia del servidor: quién puede conectarse, qué archivo CCD recibe y si se concede o no la propiedad por defecto de la salida.

Por eso un iroute por defecto es una decisión amplia de confianza. La salida debe aceptar legítimamente tráfico de vuelta de direcciones de internet arbitrarias, y debe ser una máquina que controles, parchees y vigiles. Dar la misma propiedad a un par al que no le confiarías un router es el error al que este diseño invita.

La pertenencia es el control real. Cualquier cliente que pueda configurar sus propias rutas puede intentar usar la salida, así que restringir quién puede conectarse, o a qué pares servirá la salida, forma parte del diseño y no es una idea posterior.

Fallar de forma segura cuando la salida desaparece

Desconecta la salida y la propiedad por defecto interior desaparece con su sesión. Lo que no debe pasar es que el concentrador se convierta en silencio en la salida sustituta: ninguna ruta por defecto del conjunto VPN hacia el enlace ascendente del concentrador, y ninguna regla amplia de enmascaramiento que reenviaría de buena gana el mismo tráfico. Prueba ese fallo a propósito y luego prueba la recuperación con un flujo nuevo y no con una página que ya estaba abierta.

# on the consumer, with the exit up and then down
ip -4 route get 1.1.1.1
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com

Si el tráfico del consumidor sigue llegando a internet después de que la salida se haya ido, algo más lo transporta y el límite que pretendías no existe. Trata DNS e IPv6 también como decisiones separadas: una ruta IPv4 más enmascaramiento no dice nada del tráfico AAAA, y un resolutor empujado por el concentrador responderá desde donde salga realmente la consulta.

Artículos relacionados