Nat disponible enrutando con Linux

Este hilo nace como respuesta para resolver el problema de NAT disponible cuando una o varias X360 están conectadas en una red local con direccionamiento privado. La solucion pretende ser abierta en todos los sentidos: primero solucionando el problema de NAT, permitiendo que varias X360 puedan conectarse simultaneamente, sin tener que depender de la compra de hardware específico de terceros y/o configuraciones de redireccion de puertos (este proceso se hará de forma automática, ¿increible eh?).

Lo descrito ha sido probado correctamente sobre Debian Sarge, de igual forma debe funcionar con cualquier otra distro. Si teneis dudas de cómo realizar algunas partes, no dudeis en comentarlo. Este post requiere para su compresión experiencia en Linux y esta enfocado a usuarios medios/avanzados.

Comencemos explicando cómo enrutar trafico de una red local usando como router un equipo con Linux para luego explicar cómo solucionamos de forma automática el problema de NAT.



PUNTO 1: Enrutando trafico con Linux

Primero, configurar en monopuesto el router ADSL para que asigne la IP publica al equipo Linux. Este equipo debe tener dos tarjetas de red, una conectada a la red publica con su IP de Internet y otra a la red privada, con su IP de la lan local. Los equipos de la red privada pasarán a tener esta máquina como gateway por defecto. Ahora, en las reglas de enrutados configuramos el enmascaramiento para la red local completa y el reenvio de paquetes. Suponiendo que nuestra red local es la 192.168.2.0 las reglas serian:

iptables -A POSTROUTING -s 192.168.2.0/255.255.255.0 -o eth1 -j MASQUERADE
iptables -P FORWARD DROP
iptables -A FORWARD -s 192.168.2.0/255.255.255.0 -j ACCEPT
iptables -A FORWARD -d 192.168.2.0/255.255.255.0 -j ACCEPT


El primer comando fuerza el enmascaramiento de los paquetes para la red local mientras que las otras dos habilitan el reenvio de paquetes. Además, hay que cambiar el 'eth1' por el nombre de la interfaz con la IP pública en Linux (ya que espeficia el interfaz de salida para el enmascaramiento). Para que el reenvio funcione se debe activar a nivel de kernel ip_forward, eso se puede hacer faclimente editando el fichero /etc/sysctl.conf e incluir la siguiente linea:

net.ipv4.ip_forward=1

Lo que es igual a poner un 1 en el fichero '/proc/sys/net/ipv4/ip_forward'. Al consultar las reglas iptables debes obtener lo siguiente:

root@server:/> iptables -L -n
.......
Chain FORWARD (policy DROP)
target prot opt source destination
ACCEPT all -- 192.168.2.0/24 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 192.168.2.0/24
........
root@server:/> iptables -L -n -t nat
........
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 192.168.2.0/24 0.0.0.0/0
........


Aparece mas información, solo pongo las partes relevantes. Las reglas iptables se pueden grabar para que se activen automaticamente al iniciar el sistema. Revisadlo o de lo contrario la configuración se pierde al reboot del ordenador.

LLegado a este estado, el equipo linux rencamina los paquetes de la red local a Internet, y si probais a navegar desde un ordenador configurando una IP local compatible y usando como gateway la IP del servidor Linux, debería funcionar. De igual forma, si probais la conexion de la X360 en principo os debe dar como bueno el test, pero obtendreis NAT moderada o estricta. A este nivel si probais a conectar a XBOX Live debe funcionar, pero segun que juegos habrá cosas que no podreis hacer, por ejemplo en GOW funciona todo menos el hacer de anfitrion de partidas. Vamos a solucionar este problema en el siguiente punto.



PUNTO 2: NAT disponible enrutando con Linux

Esta es la parte realmente interesante del post. El problema por el que no se obtiene un buen nivel de NAT viene de que la XBOX 360 utiliza un protocolo UPnP para la comunicación. Por defecto, los dispositivos Windows cuando activas la comparticion de internet ICS habilitan el rencaminamiento UPnP (de echo, si lo haceis y mirais las reglas avanzadas de redireccion vereis que automaticamente va metiendo reglas para la XBOX). Debemos obtener este comportamiento para Linux, ¿como hacerlo? Utilizando un servcicio llamado miniupnpd.

Primero, ir a la web del proyecto: http://miniupnp.free.fr/
Acceder a la seccion de descargas (Download) y bajar la ultima version del demonio, en el momento de escribir este post es la RC2 : http://miniupnp.tuxfamily.org/files/download.php?file=miniupnpd-1.0-RC2.tar.gz
Al descomprimirlo te crea un directorio. Mi recomendación es que lo movais al directorio /usr/local con el nombre miniupnpd. Una vez ahi, seguid los pasos descritos en el fichero INSTALL los cuales voy a detallar ahora:

- Instalar las librerias de desarrollo de iptables: En Debian es facil, ejecutar 'apt-get install iptables-dev'
- Generar el demonio: Escribir 'make -f Makefile.linux' . Esto nos compilará el demonio en el directorio actual (/usr/local/miniupnpd). Con esto ya tenemos generado el servicio, resta integrarlo para que se inicie con el arranque del sistema (incluirlo en los runlevels de inicio). El fichero de instalacion en esta parte nos dice que hagamos el script de inicio/parada por nuestra cuenta. Me he creado un script , si no quereis trabajar en este punto podeis descargar y usar el mio que está dispible en este enlace. El script está pensado para inciar el demonio suponiendo que está instalado en /usr/local/miniupnpd. Si lo vais a instalar en otro directorio, os recomiendo que reviseis la definicion de variables que se hace al comienzo del guión y las adapteis a vuestro entorno.
- Modificar los guiones de miniupnpd: El servicio utiliza un conjunto de scripts adicionales para activar/desactivar las reglas de enrutado. Debeis adaptarlos a vuestro entorno. Los guiones que debeis modifcar están en el directorio de nombre 'linux' (ruta completa: /usr/local/miniupnpd/linux). Y son los siguientes: iptables_display.sh, iptables_flush.sh, iptables_init.sh, iptables_removeall.sh. Usando vuestro editor de textos favorito (vi, joe, ...), editais cada fichero y modificais en cada caso lo requerido. Para el primer y segundo guión sólo hay que definir la variable IPTABLES que indica la localización del ejecutable iptables, en Debian "/sbin/iptables" (adaptarlo si usais otra distro). Para el tercer y cuarto guión debeis definir las variables IPTABLES (igual que antes) y EXTIF, esta última debe indicar el nombre de la interfaz con la IP externa (en mi caso, eth1). Para que quede bien claro, voy a exponer el contenido de mis guiones, una vez modificados:

root@iria:/usr/local/miniupnpd/linux> ls * | grep .sh
iptables_display.sh
iptables_flush.sh
iptables_init.sh
iptables_removeall.sh
root@iria:/usr/local/miniupnpd/linux> cat iptables_display.sh
#! /bin/sh
# $Id: iptables_display.sh,v 1.3 2006/11/23 12:32:56 nanard Exp $
IPTABLES="/sbin/iptables"

#display all chains relative to miniupnpd
$IPTABLES -v -n -t nat -L PREROUTING
$IPTABLES -v -n -t nat -L MINIUPNPD
$IPTABLES -v -n -t filter -L FORWARD
$IPTABLES -v -n -t filter -L MINIUPNPD

root@iria:/usr/local/miniupnpd/linux> cat iptables_flush.sh
#! /bin/sh
# $Id: iptables_flush.sh,v 1.2 2006/11/23 12:32:57 nanard Exp $
IPTABLES="/sbin/iptables"

#flush all rules owned by miniupnpd
$IPTABLES -t nat -F MINIUPNPD
$IPTABLES -t filter -F MINIUPNPD

root@iria:/usr/local/miniupnpd/linux> cat iptables_init.sh
#! /bin/sh
# $Id: iptables_init.sh,v 1.3 2006/11/23 12:32:57 nanard Exp $
IPTABLES="/sbin/iptables"

#change this parameters :
EXTIF=eth1
EXTIP="`LC_ALL=C /sbin/ifconfig $EXTIF | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'`"
echo "External IP = $EXTIP"

#adding the MINIUPNPD chain for nat
$IPTABLES -t nat -N MINIUPNPD
#adding the rule to MINIUPNPD
$IPTABLES -t nat -A PREROUTING -d $EXTIP -i $EXTIF -j MINIUPNPD

#adding the MINIUPNPD chain for filter
$IPTABLES -t filter -N MINIUPNPD
#adding the rule to MINIUPNPD
$IPTABLES -t filter -A FORWARD -i $EXTIF -o ! $EXTIF -j MINIUPNPD

root@iria:/usr/local/miniupnpd/linux> cat iptables_removeall.sh
#! /bin/sh
# $Id: iptables_removeall.sh,v 1.3 2006/11/23 12:32:57 nanard Exp $
IPTABLES="/sbin/iptables"

#change this parameters :
EXTIF=eth1
EXTIP="`LC_ALL=C /sbin/ifconfig $EXTIF | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'`"

#removing the MINIUPNPD chain for nat
$IPTABLES -t nat -F MINIUPNPD
#rmeoving the rule to MINIUPNPD
$IPTABLES -t nat -D PREROUTING -d $EXTIP -i $EXTIF -j MINIUPNPD
$IPTABLES -t nat -X MINIUPNPD

#removing the MINIUPNPD chain for filter
$IPTABLES -t filter -F MINIUPNPD
#adding the rule to MINIUPNPD
$IPTABLES -t filter -D FORWARD -i $EXTIF -o ! $EXTIF -j MINIUPNPD
$IPTABLES -t filter -X MINIUPNPD

root@iria:/usr/local/miniupnpd/linux>


- Configurar el servicio miniupnpd: En el directorio principal, /usr/local/miniupnpd, debe existir un fichero llamado 'miniupnpd.conf' cuyo contenido debe ser el siguiente:

root@iria:/usr/local/miniupnpd> cat miniupnpd.conf
ext_ifname=eth1
#ext_ip=
# there can be multiple listening ips
listening_ip=192.168.2.1
port=5555

# bitrates reported by daemon in Bytes per second
bitrate_up=1000000
bitrate_down=10000000

# default presentation url is http address on port 80
#presentation_url=

# report system uptime instead of daemon uptime
#system_uptime=no

# notify interval in seconds default is 30 seconds.
notify_interval=240

# log packets in pf
#packet_log=no
root@iria:/usr/local/miniupnpd>


De todos los parametros definidos, debeis especificar (editando el fichero con vuestro editor de textos favorito: vi, joe, emacs....) como mínimo el nombre de la interfaz con la IP externa (en mi caso, eth1. Opcionalmente se puede especificar la IP, pero no es necesaria (la obtiene automáticamente a partir del nombre de la interfaz)) y listening_ip que especifica la IP local donde se va a poner a la escucha (la IP local del equipo Linux). El resto de parametros no son necesarios cambiarlos para que funcione, aunque estaria bien afinarlos para adecuarlos a nuestro entorno (bitrate de subida/bajada, etc). Cada atributo va claramente explicado por lo que no creo que os surjan dudas en caso de querer retocarlos.

Con esto, ya tenemos todo listo, tendríamos que arrancar el servicio, que si lo habeis integrado en el sistema de arranque de linux (si no sabes hacerlo, preguntame) debe tener el guión en /etc/init.d/miniupnpd. Lo llamamos con 'start' ( /etc/init.d/miniupnpd start ) y el probamos de nuevo desde XBOX 360 la conexión, obtendremos NAT disponible. Si mirais el 'status' ( /etc/init.d/miniupnpd status ) del servicio una vez iniciado y probada la conectividad XBOX, automáticamente debe crearos una regla de redireccion UDP para la IP de la X360 ( generalmente, redireccion UDP del puerto 3074 ) en la nueva cadena MINIUPNPD creada automáticamente. Estas reglas serán incluidas por el servicio automaticamente cuando una X360 intente conectar, por lo que no tendreis que redirigir puerto alguno nunca mas

Se que el documento es realmente tecnico y require conocer bien Linux para no 'perderse'. Si alguien quiere probarlo estaré encantado de ayudaros, si quereis podeis alimentar este post con vuestras esperiencias al respecto y así hacer este post lo mas completo posible.
Musice escribió:Así también debería rular http://www.elotrolado.net/showthread.php?s=&postid=1559400#post1559400


En esa explicacion se configura el enrutado de paquetes, pero no el UPnP con lo que no irá 100%. Lo explicado ahi es similar al punto 1 del post, el punto 2 no se realiza y por lo tanto dudo que el NAT obtenido sea bueno aunque seguramente suficiente para jugar en Live en la mayoria de juegos pero sin poder crear partidas (yo he jugado al GOW ocn NAT estricta y hasta el micro funcionaba pero no podia ejercer de anfitrión).
2 respuestas