##
# 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
Descripción del código de Nightwing
0: 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!