Red NAT privada con salida al exterior en VirtualBox

Una de las cosas que más echo en falta en VirtualBox con respecto a cuando trabajaba con VMware Workstation o Player, al trabajar una máquina local para hacer pruebas, es que estas últimas te creaban varios tipos de redes por defecto que VirtualBox no hace. La más útil para mi, sobre todo cuando estás en un cliente en el que es difícil solicitar IPs o cuando quieres crear una red interna de pruebas, es crear una red privada de la que formen parte tanto las máquinas virtuales como la propia máquina anfitriona, y que tenga salida al exterior mediante NAT.

En las últimas versiones de VirtualBox (a partir de la 4.3, en modo experimental) existe el llamado NAT Service, que simula el comportamiento anterior de VMware, pero que no permite la conexión desde la máquina anfitriona (ya que, al contrario que VMware, VirtualBox no crea una interfaz virtual para esta red) hacia las máquinas virtuales o a la inversa. Esto es muy cómodo cuando quieres hacer SSH hacia las máquinas virtuales, ya que no tienes que estar redirigiendo puertos, que es la única forma de hacerlo con VirtualBox en el modo NAT Service (y no digamos si tienes varias máquinas virtuales, el lío de redirección de puertos y parámetros al SSH para conectar a las diferentes máquinas virtuales).

Buscando una solución alternativa y lo más transparente y sencilla de gestionar, hace tiempo descubrí esta página que lo que hace es crear una interfaz virtual en la máquina anfitrión, configurando el reenvío TCP y un servidor Dnsmasq para servir direcciones por DHCP y la resolución DNS de esa red. De esta forma, si la red de las máquinas virtuales se configura en modo bridge, usando la interfaz creada, todas podrán comunicarse entre sí y con la máquina anfitrión, aparte de tener un servidor DHCP y DNS (por lo que podremos crear asignaciones de direcciones estáticas, entradas DNS para un dominio ficticio interno, etc.). Además, las máquinas virtuales tendrán salida al exterior, ya que la máquina anfitrión realizará NAT del tráfico saliente que se reciba desde esta red. Incluso podemos montar un servidor PXE para arrancar sistemas en red o la instalación automática mediante Kickstart, Clobber o Preseed.

Para rizar aún más el rizo, decidí simplificar la configuración. La anterior está bien, pero es necesario tener bastantes cosas en cuenta (la interfaz, el paquete bridge-utils, el reenvío TCP, la configuración de Dnsmasq, etc.), y se complica a mayores cuando quieres tener varias redes virtuales separadas y que se comuniquen entre sí. Buscando un poco más, descubrí esta página en la que se combinan todos los pasos anteriores en un único punto. En resumen, lo que se hace es crear una interfaz virtual, y en los precomandos y postcomandos al levantar y apagar la interfaz, se ejecutan todos los pasos necesarios. Para poner en marcha esto, lo primero será instalar Dnsmasq y los paquetes necesarios para crear la interfaz virtual:

apt-get install dnsmasq vde2 bridge-utils
update-rc.d dnsmasq disable
Es necesario deshabilitar dnsmasq del arranque ya que la configuración por defecto escucha por todas las interfaces, y al levantar dnsmasq por cada interfaz virtual, da un error diciendo que la dirección ya está en uso.

Para no tener que tocar mucho el archivo /etc/network/interfaces, y poder gestionar más fácilmente las interfaces virtuales que creemos, configuraremos el sistema para que cargue dinámicamente todos los archivos de configuración desde el directorio /etc/network/interfaces.d; para ello, tendremos que añadir, si no existe ya, esta línea:

auto lo
iface lo inet loopback

source /etc/network/interfaces.d/*.cfg

Y por supuesto, crear dicho directorio:

mkdir -p /etc/network/interfaces.d

A continuación, ya podemos definir la interfaz (fichero /etc/network/interfaces.d/vnet0.cfg):

auto vnet0
iface vnet0 inet static

  address 192.168.77.253
  netmask 255.255.255.0


  ############################################################################################################
  # Arranque de la interfaz
  ############################################################################################################

  # Crear la interfaz virtual
  pre-up /usr/bin/vde_switch --tap ${IFACE} --daemon --group vde2-net --sock /var/run/${IFACE}.ctl \
   --mod 775 --mgmtmode 770 --mgmt /var/run/${IFACE}-manage --pidfile /var/run/${IFACE}_vde.pid

  # Comprobamos si existe un archivo de configuración de Dnsmasq, y si no existe, creamos uno vacío
  # para que no se queje el proceso de Dnsmasq al levantarlo
  up test -e /etc/dnsmasq_${IFACE}.conf || touch /etc/dnsmasq_${IFACE}.conf

  # Levantar el proceso de Dnsmasq, pasando como interfaz a la que asociarse la propia interfaz y el
  # rango DHCP para asignar direcciones (la dirección de la interfaz definida arriba debe estar en este
  # rango); se pueden especificar más parámetros añadiéndolos aquí o creando/modificando un archivo
  # de configuración según la instrucción anterior.
  up /usr/sbin/dnsmasq --interface=${IFACE} --except-interface=lo --bind-interfaces --user=nobody \
     --dhcp-range=${IFACE},192.168.77.101,192.168.77.199,8h \
     --local=/pruebas.intra/ --domain=pruebas.intra \
     --pid-file=/var/run/${IFACE}_dnsmasq.pid --conf-file=/etc/dnsmasq_${IFACE}.conf

  # Añadir una regla a iptables para natear el tráfico saliente de esta red
  post-up iptables -t nat -I POSTROUTING -s 192.168.77.0/24 -j MASQUERADE


  ############################################################################################################
  # Parada de la interfaz
  ############################################################################################################

  # Eliminar el nateo del tráfico saliente asociada a la red
  pre-down iptables -t nat -D POSTROUTING -s 192.168.77.0/24 -j MASQUERADE

  # Parar el proceso de Dnsmasq
  down kill $(cat /var/run/${IFACE}_dnsmasq.pid) && rm -f /var/run/${IFACE}_dnsmasq.pid

  # Borrar el archivo de configuración de Dnsmasq si está vacío (para mantener limpio el sistema)
  down test -s /etc/dnsmasq_${IFACE}.conf || rm -f /etc/dnsmasq_${IFACE}.conf

  # Eliminar la interfaz virtual
  post-down kill $(cat /var/run/${IFACE}_vde.pid) || kill -9 $(cat /var/run/${IFACE}_vde.pid)

En el post original de donde saqué esta configuración (el segundo referenciado), la regla de iptables hacía referencia a la interfaz de salida, y no a la red de origen como he puesto yo. Esto lo he tenido que hacer ya que Ubuntu usa NetworkManager, y parece que levanta esta interfaz antes que las demás (por ejemplo, con la que tengamos configurada como principal como eth0 o wlan0), por lo que no es posible la interfaz de salida de la ruta por defecto (y que además esta interfaz puede cambiarse desde el escritorio). Por tanto, lo que he hecho, es que en la regla de iptables, en lugar de hacer NAT a todo lo que salga por la interfaz por defecto tras el enrutado, es hacer NAT a todo lo que venga de la red de la interfaz virtual tras el enrutado.

Esto tiene un problema, que no creo que sea difícil de solucionar, pero que no lo he hecho, y es que si hay varias interfaces virtuales y queremos comunicar máquinas de distintas redes, siempre se hará NAT, aunque no salgan del propio host anfitrión.

El único paso que he dejado fuera es la configuración del reenvío TCP, ya que no está ligado a una interfaz en concreto, sino que va a nivel de sistema.

net.ipv4.ip_forward=1

Recargamos la configuración para que se aplique el cambio anterior:

sysctl -p

Las ventajas de esta configuración sobre la primera es que:

  • Se levanta un proceso Dnsmasq distinto para cada interfaz, con un archivo de configuración específico, por lo que se pueden agregar en el fichero datos que no se pasan directamente al programa por parámetros, como asignaciones de IPs estáticas, registros DNS, etc.
  • Se pueden tener varias interfaces virtuales, cada una con su propia configuración DNS, simplemente creando una nueva interfaz copiando y pegando tantas veces el bloque anterior y modificando los datos mínimos (sobre todo la dirección IP, el rango DHCP y las reglas de iptables), o creando un archivo distinto por cada interfaz en el directorio /etc/network/interfaces.d.

Para finalizar, se puede modificar la configuración de Dnsmasq para personalizar las asignaciones DHCP, la resolución DNS, así como hacer que los sistemas arranquen desde la red con PXE; hay configuraciones de ejemplo en esta página.

comments powered by Disqus