Descripción del código del script /etc/init.d/nightwing
De LugroMesh
## # Copyright (C) LUGRo-Mesh # Licencia: Creative Commons Atribución 2.5 de Argentina # Contact list: lugro-mesh-dev@lugro.org.ar # Versión 1.0
Tabla de contenidos |
Descripción del código de Nightwing
0: Intro
El presente es un documento que intentará explicar el funcionamiento del código desarrollado y utilizado para el funcionamiento del firmware libre Nightwing, el cual es utilizado por el proyecto LUGRo-Mesh.
LUGRo-Mesh comienza como una iniciativa de montar una Red Libre utilizando tecnología de redes Mesh.
El código trata de seguir un lineamiento: ser simple y auto explicativo.
Así y todo se decide realizar este simple resumen que explica su funcionamiento para permitir sumar personas a su desarrollo y que les sirva para poder entender mejor como funciona.
Para poder realizar esta tarea se tomarán fragmentos del código y se agregarán los comentarios necesarios.
1: El inicio.
El firmware Nightwing tiene como base principal un script de inicio homónimo alojado en /etc/init.d. Este script realiza las configuraciones necesarias para que se seteen distintas partes del sistema para poder, al terminar, tener corriendo un sistema que cumpla el propósito fijado por el proyecto.
Dado que es un script de inicio y que el mismo está funcionando según las formas de OpenWrt, se establece el momento en que se ejecutará mediante el seteo de la variable "START" al principio del script. Esto será tomado por OpenWrt para determinar su inicio y el momento del mismo.
START=96
start (){
2: Las variables.
Luego de setear esta variable y dar comienzo a la sección start propia del script, se procede a setear las variables necesarias para el funcionamiento del script.
Estas variables se setean principalmente utilizando el sistema "uci" que permite leer/escribir/modificar valores en archivos de configuración.
## values
MESH_PREFIX=$(uci get network.mesh.ipaddr|awk -F "." '{print $1}')
PUBLIC_AP_NETMASK=$(uci get network.public.netmask)
PRIVATE_AP_NETMASK=$(uci get network.private.netmask)
PUBLIC_AP_IFACE=$(uci get network.public.ifname)
PRIVATE_AP_IFACE=$(uci get network.private.ifname)
MESH_IFACE=$(uci get network.mesh.ifname)
LAN_IFACE=$(uci get network.lan.ifname)
TUNNEL_IFACE="bat0"
## Parameters for B.A.T.M.A.N.-Experimental
## Choose the algorithm to found a gateway
ROUTING_CLASS=$(uci get bmxd.general.routing_class)
ORIGINATOR_INTERVAL=$(uci get bmxd.general.originator_interval)
BMX_ARGS=" -o $ORIGINATOR_INTERVAL"
GATEWAY_CLASS=$(uci get bmxd.general.gateway_class)
GATEWAY_IP=$(route -n | grep -A 4 UG | awk '{ print $2}')
MASK=$(ifconfig $LAN_IFACE | grep Mask | cut -d : -f 4)
LAN_MAC=$(ifconfig $LAN_IFACE | grep HWaddr | awk '{print $5}')
WIFI0_CHANNEL=$(uci get wireless.wifi0.channel)
## Options
DNSMASQ_OPTIONS=" --bind-interfaces \
--resolv-file=/etc/resolv.conf.opendns -I $MESH_IFACE,$TUNNEL_IFACE"
3: Las rutas
En el desarrollo del script creímos importante determinar unívocamente las rutas a cada uno de los programas externos utilizados y a los archivos de configuración.
Notaran que muchos de estos archivos de configuración están apuntando a /tmp. Esto resulta así dado que se quiso preservar la vida útil de la memoria flash de los dispositivos, la cual sabemos es muy sensible a la escritura y que tiene un ciclo reducido que podría ocasionar que la misma se dañe y con ellos, dejar el dispositivo inutilizable. De allí, dado que /tmp es memoria RAM y no flash, y dado también que se opta por que la configuración se reescriba en cada arranque, es que se tome ese camino.
## Paths BMXD=/usr/sbin/bmxd BMX_MODE_CONF=/etc/config/bmx_mode RESOLV_CONF=/etc/resolv.conf DNSMASQ_CONF=/tmp/dnsmasq.conf DNSMASQ=/usr/sbin/dnsmasq WIFIDOG_CONF=/tmp/wifidog.conf IFCONFIG=/sbin/ifconfig IWCONFIG=/usr/sbin/iwconfig IPTABLES=/usr/sbin/iptables
4: Cálculos
Existen varios cálculos que se realizan en el script. Uno de ellos es el que permite determinar un rango de IP único para cada nodo y que también sirve para determinar su ID.
Esto se hace a partir de una función llamada hex2dec que originalmente es del sistema Ro.B.In., del cual originalmente se obtuvieron ideas para el desarrollo de éste sistema.
La función determina un número decimal a partir de la MAC ADDRESS de la interfaz LAN, lo cual garantiza en cierto punto que el rango de direcciones IP y el ID seleccionado, será único entre los nodos de la red.
hex2dec () {
local i=$1
let x=0x$(echo $LAN_MAC | cut $i)
echo $x
}
La función se utiliza invocándola para setear otra variable. Se utiliza una variable general para las IP llamada IP_BASE. A partir de ella se setean las distintas ip y rangos utilizados.
## Define Net base for VAP's
IP_BASE="$(uci get network.public.ipaddr| \
awk -F "." '{print $1}').$(hex2dec -c13-14).$(hex2dec -c16-17)"
## PUBLIC_AP IP
IP_PUBLIC_AP="${IP_BASE}.1"
5: Parada de servicios no utilizados.
Existen diversos servicios los cuales no son necesarios para el funcionamiento del sistema Nightwing y que a fín de no ocupar recursos son parados y deshabilitados en el arranque. Esta comprobación sólo tiene efecto una vez, cuando recién está flasheado el firmware en el dispositivo. Para ello se comprueba si existe un link simbólico, en /etc/rc.d/, del servicio. En caso de que exista, se para el servicio y se lo desactiva.
## Stop and disable not needed services if [ -f /etc/rc.d/S50httpd ]; then /etc/init.d/httpd stop /etc/init.d/httpd disable fi if [ -f /etc/rc.d/S60dnsmasq ]; then /etc/init.d/dnsmasq stop /etc/init.d/dnsmasq disable fi ## Check if bmxd daemon is running, if so stop and disable it. if [ -f /etc/rc.d/S91bmxd ]; then killall bmxd /etc/init.d/bmxd disable fi
6: El WiFiDog.
Para nuestro sistema se utiliza WiFiDog y dado que el sistema es 0-conf, se determinan automáticamente variables que serán utilizadas por el sistema.
Esta configuración se realizará también una sola vez en el primer arranque. Notar que todo el seteo de archivos de configuración está dentro de un IF que desactiva el WiFiDog existente, el cual será levantado por el propio script de init de Nightwing en cada arranque:
## Check if WiFiDog daemon is running, if so stop and disable it and change some configs. if [ -f /etc/rc.d/S50wifidog ]; then /etc/init.d/wifidog stop /etc/init.d/wifidog disable
Luego de haber deshabilitado el inicio de WifiDog, se determina el ID utilizando la función nombrada en el punto 4:
## Determine nodo_id for the first time. Then it could be changed. NODE_ID=$(hex2dec -c13-14)$(hex2dec -c16-17)
Luego se setean, utilizando uci, los archivos de configuración que serán utilizados en cada arranque posterior.
uci set wireless.public.ssid=lugro-mesh-node-${NODE_ID}
uci set wireless.private.ssid=lugro-secure-node-${NODE_ID}
Notar que se setea también el essid por primera vez. Luego el mismo será seteado al levantarse los distintos VAP's en cada inicio. Dado que este seteo sucede antes de que el script se ejecute, y que al ejecutarse por primera vez los VAP's ya están levantados, se fuerza el nuevo essid calculado con el NODE_IP. Motivo por el cuál, despues del primer arranque luego de flashear, es que se puede llegar a ver 2 AP demás.
$IWCONFIG $PUBLIC_AP_IFACE essid lugro-mesh-node-${NODE_ID}
$IWCONFIG $PRIVATE_AP_IFACE essid lugro-secure-node-${NODE_ID}
Se vuelca luego el NODE_ID y se hace commit de todo para que quede guardado en los archivos de configuración.
uci set wifidog.node.id=$NODE_ID uci commit wifidog uci commit wireless
El archivo de configuración propio del sistema WiFiDog también requiere ser seteado con los nuevos valores. Para ello el sistema se basa en un archivo wifidog.conf de base, el cual se cambia por medio del programa "sed":
## Set config for WiFiDog
sed -i '
{
/GatewayID/s/GatewayID default/GatewayID '$NODE_ID'/;
s/GatewayAddress/GatewayAddress '$IP_PUBLIC_AP'/;
}' /etc/wifidog.conf
Al terminar de setear los datos que no cambiarán más en cada arranque, se cambia el nombre del archivo de configuración y se hace un enlace simbólico a un archivo en /tmp. Ya que en cada arranque existen cosas que cambian en WiFiDog, y como comentamos anteriormente no queremos que la flash se dañe.
El último "fi" declara el final de toda la sentencia de comprobación de WiFiDog.
mv /etc/wifidog.conf /etc/wifidog.conf.sample ln -s $WIFIDOG_CONF /etc/wifidog.conf
fi
El sistema se está preparando desde su diseño para que pueda ser simple y sencillo de modificar si el usuario así lo desea. Es por esto que el script de Nightwing comprobará en cada arranque si la configuración de WiFiDog ha cambiado en algún aspecto. Por ejemplo, en el servidor de WifiDog o en el usuario y pass para entrar a ver los valores que el gateway WiFiDog vuelca en cada nodo.
Esto se logra simplemente comprobando una bandera que está en 1 en el primer inicio y que luego es seteada a 0. De esta forma, si se necesita cambiar algo en éste archivo, hay que recordar poner en 1 la bandera para que los cambios tomen efecto.
Esto deja preparado el sistema para que luego se pueda integrar algún mecanismo que permita que el usuario haga los cambios más fácilmente.
## Check if WiFiDog config has changed
if [ "$(uci get wifidog.node.change)" == 1 ]; then
sed -i '
{
/HTTPDUserName/s/HTTPDUserName .*/HTTPDUserName '$(uci get wifidog.node.HTTPDUserName)'/;
/HTTPDPassword/s/HTTPDPassword .*/HTTPDPassword '$(uci get wifidog.node.HTTPDPassword)'/;
/Hostname/s/Hostname .*/Hostname '$(uci get wifidog.node.server)'/;
/SSLAvailable/s/SSLAvailable .*/SSLAvailable '$(uci get wifidog.node.ssl)'/;
} ' /etc/wifidog.conf.sample
uci set wifidog.node.change=0
uci commit wifidog
fi
Seteado todo y como comentamos anteriormente, se vuelca el archivo a la memoria RAM y dado que ya se ha establecido un enlace, WiFiDog podrá leer los datos.
## Write wifidog.conf in /tmp cp /etc/wifidog.conf.sample $WIFIDOG_CONF
7: Comencemos a rockear
Aquí comienza la magia. Lo primero que hará el script, luego de haber seteado todo lo necesario para comenzar a funcionar, es determinar en que modo se pondrá. El mismo puede setearse en 2 modos: Cliente o Gateway. El modo Gateway significa que tiene enlace a Internet, y de ésta forma se anunciará para que los nodos que no lo tengan y sean seteados en modo Cliente, lo conozcan y puedan utilizarlo para brindar Internet a quiénes se conecten allí.
Todo ésto lo hace el mismo B.A.T.M.A.N., pero hay que indicarle a B.A.T.M.A.N. como funcionar en cada caso y es por ello que se hace ésta división en el código y en la forma de configurar.
Esto implica, por ejemplo, saber si puede salir a Internet. Para ésto se basa en que el mismo OpenWrt, al principio, trata de tomar una dirección IP vía DHCP.
Por supuesto, puede pasar que se tome una dirección IP por DHCP pero que no se tenga salida a Internet, por lo que se comprobará mediante el uso de la herramienta fping, si se puede llegar por lo menos a uno de 3 root server. Se toman 3 root server y no dominios fqdn para evitar tener problemas con la resolución de nombres. Así también, se conviene que si hay Internet, por lo menos uno de éstos root server responderá. En caso que no lo haga, los problemas son mayores por que países enteros se han quedado sin Internet :D (por lo menos los que están dependiendo de alguno de los 3 root server :D).
## Discover its own role. ## If we have Internet access, then the node is a gateway. Otherwise is a client. if [ $(fping -a 192.5.5.241 192.36.148.17 192.58.128.30 2>/dev/null|wc -l) == 0 ];
En este punto, si ninguno de los 3 root server a contestado, se verifica si se ha tomado IP por DHCP. Luego de ésto se hace otra comprobación, y es que si la IP que se tomo es del rango utilizado por el sistema zeroconf de avhai autoipd en cuyo caso nigthwing se ponrá en en modo cliente. De no hacerse esta comprobación nightwing creería que hay un server de dhcp en la red sin salida a internet y se rebooteara para no instalar un segundo server de dhcp en el mismo segmento de ethernet.
Sin embargo, cuando el dhcp server esta en el rango zeroconf, ahi si nightwing debe asumir el rol de cliente y proveer a la red local de internet.
then
{
if [ $GATEWAY_IP ]; then
if [ $(echo $GATEWAY_IP|cut -c1-7) == "169.254" ]; then
logger -s -t "nightwing" "Mode client, Zero Configuration Networking detected"
MODE="client"
Ahora bien, si no se ha podido comunicar a Internet, pero se tiene una IP "valida", estamos en un problema. Posiblemente se ha caído la conexión a Internet por lo que se hará reiniciar el dispositivo. Hay que tener cuidado en ésto por que puede dejar el dispositivo en un bucle continuo de reinicios.
Esta medida se tomo para brindar el mecanismos 0-conf detallado anteriormente y en el resto de la documentación.
Pero, tenga en cuenta esto si ve que su dispositivo se reinicia constantemente.
NOTA: Otra cosa a tener en cuenta y que encontrará en otras partes de los archivos del sistema, es que se hacen 2 comprobaciones adicionales sobre este particular. La primera de ella es utilizando el sistema Hotplug que se detallará más adelante. La otra es que cada 3 minutos se volverá a hacer la comprobación de si se llega a alguno de los root server (ver: /usr/bin/nw_check).
En caso de que no se llegue y que el dispositivo este en modo gateway, entonces se reiniciará para que pase al modo Cliente, o bien, siguiendo las comprobaciones anteriores, volver a tomar su modo Gateway. Esto permite, por ejemplo, que existiendo una red establecida, nadie dentro de la misma se quede sin acceso a Internet mientras exista por lo menos un nodo que tenga acceso; y lo mejor de todo, ésto se hace de forma automática.
else logger -s -t "nightwing" "Reboot - Have a Gateway, but not internet link" reboot # If I don't have Internet access, but I do have a Gateway # obtained thru dhcp, reboot and wait for service restablishment. # This helps to avoid a black hole. fi
Si no se llega a Internet y no se obtiene IP, entonces se hace que el dispositivo este en modo Cliente.
else MODE="client" fi }
Caso contrario, se hace que sea modo Gateway
else MODE="gateway" fi
Se escribe entonces la configuración utilizando la herramienta uci nuevamente, de forma de poder determinar el modo en que está el dispositivo desde fuera del script.
### Write bmx mode echo "config bmx_mode node" > $BMX_MODE_CONF echo " option mode" >> $BMX_MODE_CONF uci set bmx_mode.node.mode=$MODE uci commit bmx_mode
8: Calculemos las IP.
Utilizando la variable antes seteada en el punto 4, se configurán todas las IP necesarias y los rangos que se utilizarán para otros servicios, como por ejemplo el DHCP.
## Calculate the IP for all ifaces
##
## PRIVATE_AP IP
IP_PRIVATE_AP="${IP_BASE}.129"
## LAN IP
IP_LAN="${IP_BASE}.193"
## Calculate IP mesh iface based on MAC address in the subnet 5.x.x.x
IP_MESH="${MESH_PREFIX}.$(hex2dec -c10-11).$(hex2dec -c13-14).$(hex2dec -c16-17)"
Luego se levantan las interfaces.
## Up PUBLIC iface $IFCONFIG "$PUBLIC_AP_IFACE" "$IP_PUBLIC_AP" netmask "$PUBLIC_AP_NETMASK" ## Up PRIVATE iface $IFCONFIG "$PRIVATE_AP_IFACE" "$IP_PRIVATE_AP" netmask "$PRIVATE_AP_NETMASK" ## Up MESH iface $IFCONFIG "$MESH_IFACE" "$IP_MESH"
Debido a un problema en MadWifi el cual todavía no parece estar resuelto, se tiene que forzar el canal que se utilizará. Esperamos poder deshacernos de este bug y de éstas líneas en el futuro.
## Workaround to buggy MADWiFi HAL. Reconfigure to selected channel $IWCONFIG "$MESH_IFACE" "channel" "$WIFI0_CHANNEL"
Ahora se calculan los lease de DHCP utilizados en cada VAP.
## Calculate range and lease for PUBLIC_AP dhcp server.
PUBLIC_AP_S_LEASE="${IP_BASE}.2" ; PUBLIC_AP_E_LEASE="${IP_BASE}.126"
RANGE_PUBLIC="${PUBLIC_AP_S_LEASE},${PUBLIC_AP_E_LEASE},${PUBLIC_AP_NETMASK},12h"
## Calculate range and lease for PRIVATE_AP dhcp server.
PRIVATE_AP_S_LEASE="${IP_BASE}.130" ; PRIVATE_AP_E_LEASE="${IP_BASE}.190"
RANGE_PRIVATE="${PRIVATE_AP_S_LEASE},${PRIVATE_AP_E_LEASE},${PRIVATE_AP_NETMASK},12h"
Y se vuelca la información a un archivo de configuración para ser utilizado por el sistema Dnsmasq, el cual provee de DHCP y DNS al sistema. Al final se setea al propio Dnsmasq como nameserver del dispositivo.
## Write DNSMASQ conf for every VAP (PUBLIC & PRIVATE) cat > $DNSMASQ_CONF << EOF domain-needed bogus-priv filterwin2k dhcp-leasefile=/tmp/dhcp.leases dhcp-authoritative dhcp-range=public,$RANGE_PUBLIC dhcp-option=public,3,$IP_PUBLIC_AP dhcp-range=private,$RANGE_PRIVATE dhcp-option=private,3,$IP_PRIVATE_AP EOF # Using dnsmasq for local nameserver echo -n > $RESOLV_CONF echo "nameserver 127.0.0.1" > $RESOLV_CONF
9: Iniciamos según el modo
Como comentamos antes, según el modo, el firmware arancará de diversa forma. Modo Gateway (tengo Internet y lo anuncio) o modo Cliente (no tengo Internet directamente, pero la busco).
9.1: El modo Gateway
En este modo se tienen algunos cuidados especiales por el hecho que se tendrá que tener un delicado control de que nada pase a la red interna a la cual se conectará el dispositivo. Así también que el BMX será seteado de forma que se lo permita ver en la red como un recurso para acceder a Internet.
case $MODE in gateway) logger -s -t "nightwing" "The node is a Gateway" logger -s -t "nightwing" "Start WiFiDog captive portal ... "
Primero arrancamos WiFiDog. Debido a que generalmente los dispositivos de router wireless no son una luz en cuanto a su velocidad, se tiene que esperar un tiempo a que las reglas de iptables que el sistema WiFiDog necesita se implementen correctamente. En caso contrario podrían darse situaciones no fácilmente predecibles y totalmente indeseables.
Se elige entonces un tiempo conservador de 10 segundos de espera. Este tiempo podrá variar, cuando la tecnología avance, por ejemplo.
/etc/init.d/wifidog start # Wait 10 seconds for iptables rules sleep 10 logger -s -t "nightwing" "WiFiDog captive portal started "
Aquí volvemos a un punto que vimos anteriormente y es sobre las comprobaciones.
Estando en modo Gateway y si se detecta que se ha conectado un cable al dispositivo LAN y este brinda IP, entonces se comprobara si la misma es distinta a la que tenía primariamente. Caso contrario, se reiniciará. Este evento lo desata el Hotplug automáticamente. (Ver: /etc/iface/20-nw_change)
### Write IP of LAN_IFACE
IP_LAN="$($IFCONFIG $LAN_IFACE| awk 'NR==2 {print $2}'| awk -F: '{print $2}')"
echo "$IP_LAN" > /tmp/current-${LAN_IFACE}-ip
Se levanta el Dnsmasq con las opciones antes seteadas.
## DNSMAQ up for every VAP
$DNSMASQ_OPTIONS="${DNSMASQ_OPTIONS},$LAN_IFACE"
$DNSMASQ -C $DNSMASQ_CONF $DNSMASQ_OPTIONS
logger -s -t "nightwing" "DNSMasq started"
Se comienza a verificar el seteo de BMX y en caso de que no exista uno determinado por el usuario, se ponen valores por defecto
## Start bmxd – B.A.T.M.A.N.-Experimental logger -s -t "nightwing" "Starting bmxd ... " ## Check if gateway_class is set. If not, set to a default value of 5000. ## Set it properly at /etc/config/bmxd ! if [$GATEWAY_CLASS == ""]; then GATEWAY_CLASS="5000" fi ## Check if originator_interval is set. If not, set to a default value of 5000. ## Set it properly at /etc/config/bmxd ! if [$ORIGINATOR_INTERVAL == ""]; then BMX_ARGS="-o 2000" fi
Habiendo sido seteadas las variables, se inicia el demonio y se escriben lo argumentos utilizados en un archivo en el /tmp para poder comprobar luego como inicio.
Se puede ver que se le indica al demonio que será un gateway.
BMX_ARGS="${BMX_ARGS} -g $GATEWAY_CLASS"
BMX_ARGS="${BMX_ARGS} $MESH_IFACE"
echo $BMX_ARGS > /var/run/bmxd.arg
$BMXD $BMX_ARGS
logger -s -t "nightwing" "bmxd started"
Luego se comienzan a implementar diversas reglas de iptables que se necesitan para el funcionamiento, así como para proteger a la red interna. La primera de ellas es la de setear el postrouting para que todo el que se conecte al dispositivo pueda salir a Internet.
logger -s -t "nightwing" "Starting to apply iptables rules ..." ## SNAT $IPTABLES -t nat -I POSTROUTING -o $LAN_IFACE -j SNAT --to-source $IP_LAN
Se realiza una comprobación de la IP pública, por la que se está saliendo, para poder luego aplicar una regla que la proteja desde dentro de la red Mesh establecida.
La misma se vuelca a un archivo que luego es consultado por el script /us/bin/nw_check.
#We detect public IP Internet automatically #INET_PUBLIC_IP=$(wget -q -O- http://www.whatismyip.com/automation/n09230945.asp) INET_PUBLIC_IP=$(wget -q -O- http://lugro-mesh.org.ar/whatismyip.php) echo "$INET_PUBLIC_IP" > /tmp/current-wan-ip
Se cierra el acceso a ssh al propio dispositivo salvo para algunas interfaces.
## Close ssh port except local LAN and PRIVATE iface $IPTABLES -I INPUT -p tcp --dport 22 -j DROP $IPTABLES -I INPUT -i $PRIVATE_AP_IFACE -p tcp --dport 22 -j ACCEPT $IPTABLES -I INPUT -i $LAN_IFACE -p tcp --dport 22 -j ACCEPT
Se cierra la IP pública de acuerdo a lo que se obtuvo anteriormente.
# By default we close any incoming traffic from PUBLIC_AP_IFACE to the IP address of the Internet. # This will block access from the public interface to resources availables only to the LAN # at the point of connection to the Internet. # If necessary enable a port for access from the public interface, you only need to add # a line with -j ACCEPT. # Ej: # $IPTABLES -I FORWARD -i $PUBLIC_AP_IFACE -p tcp --dport 80 -d $INET_PUBLIC_IP -j ACCEPT $IPTABLES -I FORWARD -i $PUBLIC_AP_IFACE -d $INET_PUBLIC_IP -j DROP
Y luego se comienza a cerrar.
Lo primero es cerrar todo el tráfico, que pase por el dispositvo, para la red interna a la que esté conectado.
## Drop external packets towards LAN
$IPTABLES -I FORWARD -d ${GATEWAY_IP}/${MASK} -j DROP
Luego se cierra toda comunicación entre los VAPs. Hay que recordar además que los clientes conectados a los VAPs están también aislados entre ellos. Por supuesto, si se quiere, esto puede modificarse.
$IPTABLES -I FORWARD -i $PUBLIC_AP_IFACE -o $PRIVATE_AP_IFACE -j DROP $IPTABLES -I FORWARD -i $PRIVATE_AP_IFACE -o $PUBLIC_AP_IFACE -j DROP
Se permite que los clientes, que estén conectados a la red privada y encriptada, puedan ver la red interna. Esto sirve para que el dueño del dispositivo tenga un buen recurso wireless y a la vez seguro para acceder a su propia red.
$IPTABLES -I FORWARD -i $PRIVATE_AP_IFACE -d ${GATEWAY_IP}/${MASK} -j ACCEPT
Se cierra cualquier tipo de conexión desde la propia red Mesh a la red interna donde está el Gateway.
$IPTABLES -I OUTPUT -s 169.254.0.0/16 -o $LAN_IFACE -d ${GATEWAY_IP}/${MASK} -j DROP
Por último, se interceptan las peticiones dns desde la interface publica y la mesh redireccionandolas al servidor de lugro-mesh para que apliquen los filtrados provistos por OpenDNS sobre material no permitido por leyes locales.
# Intercept DNS Query in PUBLIC_AP_IFACE/MESH and DNAT to lugro-mesh server $IPTABLES -t nat -I PREROUTING -i $PUBLIC_AP_IFACE -p udp --dport 53 -j DNAT --to 69.61.11.215:53 $IPTABLES -t nat -I PREROUTING -s 169.254.0.0/16 -p udp --dport 53 -j DNAT --to 69.61.11.215:53 logger -s -t "nightwing" "Finishing applying iptables rules ..." ;;
Luego de esto, el sistema ya está funcionando en modo Gateway.
9.2: El modo Cliente.
Como el modo Gateway, el modo Cliente tiene sus necesidades específicas.
La primera de ellas es que en vez de ser usada la interface LAN para salir a Internet, utilizará la interfaz que se cree por la red Mesh. Esto lo tiene que saber el WiFiDog y es un cambio que se hace en la configuración.
Luego de este cambio, se inicia el WiFiDog.
client) logger -s -t "nightwing" "The node is a Client" logger -s -t "nightwing" "Start WiFiDog captive portal ..." # WiFiDog uses Mesh interface sed -i "s/ExternalInterface .*/ExternalInterface "$TUNNEL_IFACE"/" $WIFIDOG_CONF # Start WiFiDog captive portal /etc/init.d/wifidog start logger -s -t "nightwing" "WiFiDog captive portal started"
El modo Cliente, además de los VAPs, tiene la posibilidad de conectar máquinas a una LAN. De ésta forma se podrá contar con los beneficios del acceso a la red en forma wireless pero sin tener necesidad de contar con una placa wireless. Así, se establece una nueva subred que será manejada por Dnsmasq para asignar las IP y que están en un rango distinto a los VAPs.
## Up eth0 in the corresponding subnet LAN_MASK=$(uci get network.lan.netmask) $IFCONFIG $LAN_IFACE $IP_LAN netmask $LAN_MASK
Nuevamente puede darse el caso del punto 9.1, que se conecte a la LAN un cable que brinde una IP por DHCP una vez que el dispositivo ha arrancado. De está forma se hará la comprobación de Hotplug y si hay cambio, se reinicia. Podemos estár en presencia de un futuro gateway :D. Para esto, la IP que que se genera se escribe en un archivo en /tmp.
### Write IP of LAN_IFACE
echo "$IP_LAN" > /tmp/current-${LAN_IFACE}-ip
Se establecen los lease para la LAN y se guardan en el archivo de configuración.
# Set range and lease for dhcp server
LAN_S_LEASE="${IP_BASE}.194"
LAN_E_LEASE="${IP_BASE}.254"
RANGE_LAN="${LAN_S_LEASE},${LAN_E_LEASE},${LAN_MASK},12h"
echo "dhcp-range=lan,"$RANGE_LAN >> $DNSMASQ_CONF
echo "dhcp-option=lan,3,"$IP_LAN >> $DNSMASQ_CONF
Como pasaba en el modo Gateway, se espera un tiempo a que se implementen las reglas de firewall que pone el WiFiDog. Se elige entonces un tiempo conservador de 10 segundos de espera. Este tiempo podrá variar, cuando la tecnología avance, por ejemplo.
# Wait 10 seconds for iptables rules sleep 10
Luego se comienzan a implementear diversas reglas de iptables que se necesitan para el funcionamiento.
Se cierra el acceso a ssh al propio dispositivo salvo para algunas interfaces, en este caso, se quiere que tanto el VAP privado como la LAN puedan tener acceso.
logger -s -t "nightwing" "Starting to apply iptables rules ..." ## Close ssh port except local LAN and PRIVATE iface $IPTABLES -I INPUT -p tcp --dport 22 -j DROP $IPTABLES -I INPUT -i $PRIVATE_AP_IFACE -p tcp --dport 22 -j ACCEPT $IPTABLES -I INPUT -i $LAN_IFACE -p tcp --dport 22 -j ACCEPT
Luego se cierra toda comunicación entre los VAPs. Hay que recordar además que los clientes conectados a los VAPs están también aislados entre ellos. Por supuesto, si se quiere, ésto puede modificarse.
- Drop all coming from PUBLIC_IFACE to PRIVATE_IFACE and to LAN and from PUBLIC_IFACE of other node
$IPTABLES -I FORWARD -i $PUBLIC_AP_IFACE -o $PRIVATE_AP_IFACE -j DROP $IPTABLES -I FORWARD -i $PRIVATE_AP_IFACE -o $PUBLIC_AP_IFACE -j DROP
Se cierra además lo que venga de la Mesh a la interface LAN y al VAP Público.
$IPTABLES -I OUTPUT -s 169.254.0.0/16 -o $LAN_IFACE -d ${IP_LAN}/${LAN_MASK} -j DROP
$IPTABLES -I OUTPUT -s 169.254.0.0/16 -o $PUBLIC_AP_IFACE -d 10.0.0.0/8 -j DROP
logger -s -t "nightwing" "Finishing applying iptables rules ..."
Se levanta el Dnsmasq.
## Start DNSMAQ on every iface $DNSMASQ -C $DNSMASQ_CONF $DNSMASQ_OPTIONS logger -s -t "nightwing" "DNSMasq started"
Se inicia el demonio y se escriben lo argumentos utilizados en un archivo en /tmp para poder comprobar luego como inicio.
## Set bmx arguments
## Check if routing_class is set. If not, set to a default value of 1.
## Set it properly at /etc/config/bmxd !
if [$ROUTING_CLASS == ""]; then
ROUTING_CLASS="1"
fi
## Check if originator_interval is set. If not, set to a default value of 2000.
## Set it properly at /etc/config/bmxd !
if [$ORIGINATOR_INTERVAL == ""]; then
BMX_ARGS="-o 2000"
fi
BMX_ARGS="${BMX_ARGS} -r $ROUTING_CLASS"
BMX_ARGS="${BMX_ARGS} $MESH_IFACE"
echo $BMX_ARGS > /var/run/bmxd.arg
$BMXD $BMX_ARGS
logger -s -t "nightwing" "bmxd started"
Ahora viene una parte interesante del proceso. Puede darse el caso que un cliente no encuentre a ningún gateway para tomar Internet de él. Entonces, se quedará esperando hasta obtenerlo, o bien si obtiene Internet directamente, se cambiará de modo.
Para hacer esto, se implementa un búcle que cada cierto tiempo (en este caso son 15 segundos) comprobará si se ha descubierto algún gateway por la zona.
En caso de que lo encuentre, entonces se establecerá la comunicación con él. En caso que no, seguirá esperando.
## Waiting to find a gateway
logger -s -t "nightwing" "Waiting to find a Gateway node"
while true ; do
bgw=$(bmxd -c -d 2 | grep = | awk '{print $2}')
! [ -z $bgw ] && break
sleep 15
done
logger -s -t "nightwing" "Gateway node found"
Establecida la comunicación se realiza un masquerade para que recién en este punto, los que estén conectados al dispositvo cliente, puedan salir a Internet.
## Masquerade tun iface $IPTABLES -t nat -I POSTROUTING -o $TUNNEL_IFACE -j MASQUERADE logger -s -t "nightwing" "Masqueraded tunnel interface"
Luego de ésto, el sistema ya está funcionando en modo Gateway. Allí termina el case.
;; esac
10: El stop
Aunque no es necesario para el funcionamiento y no se querra parar el sistema Nightwing para arrancarlo nuevamente sin antes haber reiniciado el dispositivo (esto es debido a todos los seteos que hace el script, lo cual deja en caso de reiniciar Nightwing un dispositivo en un modo poco útil), se establece un procedimiento para pararlo. El mismo mata todas las instancias del demonio y para los servicios de Dnsmasq y WiFiDog.
}
stop () {
logger -s -t "nightwing" "Stopping bmx ... "
killall bmxd
killall dnsmasq
sleep 3; T=0; Tmax=15
while [ -n "$(pidof bmxd)" ]; do
echo -n "."; sleep 1; T=$(( $T + 1 ))
if [ $T -ge $Tmax ];then
echo
killall -SIGKILL bmxd
break
fi
done
/etc/init.d/wifidog stop
logger -s -t "nightwing" "stopped"
}
Llegado aquí el script se ha terminado. El mismo seguirá evolucionando seguramente y como hemos bromeado dentro del equipo de desarrollo, pero sólo tiende a 1.0 sin nunca llegar a serlo. :D
Como dice el final del script:
## Have fun!
