En este post compartiré unas pruebas y pequeña guía del protocolo de enrutamiento [Bmx7](https://github.com/bmx-routing/bmx7) para una red en malla.

Para construir una [red en malla autónoma](https://es.wikipedia.org/wiki/Red_en_malla) hace falta uno o más protocolo de enrutamiento, donde cada [nodo](https://es.wikipedia.org/wiki/Nodo_(inform%C3%A1tica)) en la red se hace descubrir, descubre a otros nodos, avisa a sus vecinos a quienes ha descubierto y también ayuda a llevar información de un nodo a otro a través de el mismo.

Existen varios protocolos de enrutamiento para redes *mesh* como Batman-adv, Babel, OLSR, bmx6, etc. y en el proyecto [LaOtraRed](https://wiki.lapaz.laotrared.net) hemos estado probando varios y buscando el protocolo que más se ajuste a las necesidades de una red libre comunitaria y de control colectivo. En ese afán hemos estado trabajando sobre una [primera versión estable o 1VE](https://foro.laotrared.net/t/discusion-rumbo-a-la-primera-version-estable-de-laotrared/211) donde hemos definido el protocolo **bmx7 como el principal**.

## Sobre bmx7 ##

Este protocolo es una versión más segura de [bmx6](http://bmx6.net/projects/bmx6). Bmx6 siendo una modificación de [Batman-adv](https://www.open-mesh.org/projects/batman-adv/wiki), está enfocado a redes en malla (que es lo mismo que decir redes *mesh*) pero le agrega soporte para IPv6, mejora la difusión del estado de cada nodo, etc [ [1] ](http://dsg.ac.upc.edu/sites/default/files/1569632801.pdf).

Bmx7 además le agrega seguridad usando SEMTOR lo que hace que los anuncios de rutas estén firmados criptográficamente [ [2] ](https://pdfs.semanticscholar.org/1752/f3710783f55784f8cf38a35cd5789bed8125.pdf).

A pesar de lo complejo que se ve el protocolo, configurar enrutadores para que lo utilicen es sencillo una vez se consigue poner el software necesario en el equipo.

## Preparando el escenario ##

![Escenario de prueba](/static/imgs/posts/bmx7-ep1.jpg)

Son básicamente dos nodos, el nodo A y el nodo B se descubren y establecen comunicación con la ayuda de bmx7. El nodo A tiene la dirección IPv6: fa99:1:a::a y también IPv4: 10.64.1.1, de manera similar el nodo B tiene sus propias direcciones IP.

En el escenario descrito A y B anuncian también bloques de red, por ejemplo A dirá que es acreedor del bloque IPv6 `fa99:1:a::/48` directamente y también anuncia un bloque IPv4: `10.64.1.1/24` a través de un túnel, la manera de hacer anuncios varía en bmx7 y veremos eso más adelante.

La idea de este escenario es que se puede hacer que un nodo le diga a toda la red y más específicamente a sus vecinos, que tiene conexión a un grupo de direcciones IP (bloque IP) y que a través de si mismo los demás nodos de la red pueden conectarse a los dispositivos sean cuales fueren dentro de los bloques que anuncia.

## Preparando los nodos ##

Vamos a configurar paso a paso ambos enrutadores, para esta prueba he usado dos modelos de enrutadores baratos, el TP-link mr3040 y mr3020.

Normalmente bastaría con descargar la última versión estable del sistema operativo **openwrt** o lede para estos enrutadores desde [https://downloads.lede-project.org/releases/17.01.4/targets/ar71xx/generic/](https://downloads.lede-project.org/releases/17.01.4/targets/ar71xx/generic/) y buscando las imagenes `.factory.bin` o `.sysupgrade.bin` para el mr3020 y 3040 respectivamente. Luego instalar los paquetes necesarios con:

    :::bash
    opkg install bmx7 libmbedtls bmx7 bmx7-uci-config \
    bmx7-iwinfo bmx7-tun bmx7-table kmod-iptunnel6 \
    kmod-ip6-tunnel kmod-iptunnel4 kmod-iptunnel

Las imágenes de firmware por defecto en el repositorio de paquetes de lede u openwrt vienen con la interfaz `luci` para administrar el enrutador.

Debido a que bmx7 usa criptografía para firmar paquetes y verificar autenticidad, requiere la biblioteca [mbedtls](/posts/probando-mbedtls/) instalada en el sistema, como los enrutadores mr3020 y 3040 **sólo tienen 4MB** de memoria FLASH, si se incluye el luci no hay cabida para bmx7. En modelos de enrtuadores con 8 MB  de FLASH no se tiene esta limitación.

Una solución sería desinstalar completamente luci pero no he encontrado una forma sencilla de hacerlo, por lo que se puede construir imágenes de firmware usando buildroot o image-generator, en el post [construir imágenes de firmware para enrutadores con build root](/posts/construir-firmware-para-enrutadores-con-buildroot/) puedes ver cómo hacerlo.

Por ejemplo usando el [image-generator](https://openwrt.org/docs/user-guide/additional-software/imagebuilder) se puede construir imágenes de firmware **sin luci** y con las dependencias necesarias para bmx7 con:

    :::bash
    make image PACKAGES="-libiwinfo-lua -liblua -libubus-lua -libuci-lua \
    -lua -luci -luci-app-firewall -luci-base -luci-lib-ip -luci-lib-nixio\
    -luci-mod-admin-full -luci-proto-ipv6 -luci-proto-ppp \
    -luci-theme-bootstrap -uhttpd -uhttpd-mod-ubus \
    bmx7 bmx7-iwinfo kmod-ip6-tunnel kmod-iptunnel6 kmod-iptunnel4 \
    kmod-iptunnel bmx7-json bmx7-sms bmx7-table bmx7-topology bmx7-tun\
    bmx7-uci-config libmbedtls"

--> También puedes descargar las imágenes de firmware con estas características de mi repositorio de imágenes de firmware de openwrt (este repositorio cambia y no esta garantizado que siempre vaya a funcionar):

* [https://openwrt.rmgss.net/targets/ar71xx/generic/](https://openwrt.rmgss.net/targets/ar71xx/generic/)

Luego instalar las imágenes de firmware correspondientes en los enrutadores. Si nunca lo has hecho revisa [esta guía](https://wiki.lapaz.laotrared.net/guias/instalar_openwrt).

### Configurando interfaces de red y WiFi ###

Primero el archivo de interfaces de red para el Nodo A.

#### /etc/network/interfaces

	:::bash
    config interface 'loopback'
    	option ifname 'lo'
    	option proto 'static'
    	option ipaddr '127.0.0.1'
    	option netmask '255.0.0.0'
    
    config globals 'globals'
    	# mejor no cambiar esto en el enrutador
    	option ula_prefix 'fd91:9cd6:f633::/48'
    
    config interface 'lan'
    	option proto 'static'
    	option type 'bridge'
    	option ipaddr '10.64.1.1'
    	option netmask '255.255.255.0'
    	option ifname 'eth0'
    
    config interface 'mesh'
    	option proto 'static'
    	option ip6addr 'fa99:1:a::a'

Con lo anterior configuramos dos interfaces, `lan` en IPv4 y `mesh` en IPv6.

#### /etc/config/wireless

	:::bash
    config wifi-device 'radio0'
    	option type 'mac80211'
    	option hwmode '11g'
    	option path 'platform/ar933x_wmac'
    	option htmode 'HT20'
    	option channel '2'
    	option country 'BO'
    	option txpower '18'
    	option disabled '0'
    
    config wifi-iface
    	option device 'radio0'
    	option network 'mesh'
    	option mode 'adhoc'
    	option ssid 'bmx7.pruebas'
    	option bssid 'D0:D0:11:11:11:11'
    	option encryption 'none'

Hacemos que el nodo emita una señal wifi en modo adhoc que con ssid "bmx7.pruebas" y ligada a la interfaz "mesh" definida anteriormente.

#### /etc/config/bmx7

	:::bash
    # modificamos un poco el archivo de configuracion por defecto
    # en bmx7
    config 'bmx7' 'general'
    # usando la interfaz mesh
    config 'dev' 'mesh'
            option 'dev' 'wlan0'
    
    # anuncios UHNA (para ipv6 directo)
    config 'unicastHna' 'miPrefijoDeRed'
    	option 'unicastHna' 'fa99:1:a::/48'
    
    # tuneles (para bloques ipv4)
    # anunciar tunel ipv4
    config 'tunDev' defaultbmx7
    	option 'tunDev' 'defaultbmx7'
    	option 'tun4Address' '10.64.1.0/24'
    # aceptar anuncios 
    config 'tunOut'
    	option 'tunOut' 'ip4'
    	option 'network' '10.64.0.0/16'
    
    # lo siguiente es para habilitar el plugin bmx7-tun
    # y con esto poder crear tuneles 
    config 'plugin'
            option 'plugin' 'bmx7_tun.so'
    
    config 'plugin'
            option 'plugin' 'bmx7_table.so'

En la configuración de bmx7, primero definimos en que interfaz va a trabjar el protocolo.

Luego definimos anuncios [uHNA](https://github.com/bmx-routing/bmx7#unicast-host-network-announcements-uhna) que son mensajes que anuncian a los nodos vecinos bloques y direcciones IP que tiene un nodo en la red. Lo bueno de usar UHNAs es que se garantiza que ningún otro nodo pueda utilizar las IP que anuncia un nodo mediante un identificador único y que los bloques de direcciones no se solapen. Todos estos paquetes se asocian a un indentificador único por cada nodo y van firmados criptográficamente.

Finalmente, bmx7 es sólo IPv6 y para anunciar bloques IPv4 utiliza [anuncios de túneles](https://github.com/bmx-routing/bmx7#tunnel-announcements). Afortunadamente no tenemos que crear los túneles manualemente ya que bmx7 los crea por nosotros, sólo indicamos mediante `tun4Address` que este nodo anuncia la red `10.64.1.0/24` y mediante `tunOut` le decimos que acepte anuncios que estén dentro de `10.64.0.0/16` y que los retransmita.

En el nodo B las configuraciones son similares donde sólo cambian los bloques y direcciones IP correspondientes, si habría otro nodo C o otros más se hace de la misma forma.

Una vez guardadas estas configuraciones, reiniciamos el demonio bmx7 con:

    /etc/init.d/network restart
    /etc/init.d/bmx7 restart

## Haciendo pruebas ##

El demonio bmx7 se puede consultar en cualquier momento para consultar su estado ,nodos asociados o túneles, a continuación algunas consultas hechas en el enrutador.


<div style="border:1px solid black;height:320px;width: 620px;overflow-y:hidden;overflow-x:scroll;">
<pre>
bmx7 -c status
# que responde
STATUS:
shortId  name     nodeKey cv revision primaryIp                               tun6Address tun4Address   uptime cpu txQ  nbs rts nodes 
1A0165FA openwrt RSA2048 21 0a82c7c  fd70:1a01:65fa:6d39:dce1:20b6:1299:1f82 ::/0        172.24.3.1/24 0:00:38:28 0.4 0/50 1   1   2/2
    
# se puede tambien consultar mas detalles
bmx7 -c status originators
    
# que responde
STATUS:
shortId  name     nodeKey cv revision primaryIp                               tun6Address tun4Address   uptime cpu txQ  nbs rts nodes 
1A0165FA openwrt RSA2048 21 0a82c7c  fd70:1a01:65fa:6d39:dce1:20b6:1299:1f82 ::/0        10.64.0.0/24 0:00:38:28 0.4 0/50 1   1   2/2
ORIGINATORS:
shortId  name     as S s T t descSqn lastDesc descSize cv revision primaryIp                               dev   nbShortId nbName metric hops ogmSqn lastRef 
7B037847 openwrt1   nA A A A A 512     2303     671+747  21 0a82c7c  fd70:7b03:7847:472a:414:9eee:2d98:3e14  wlan0 7B037847  openwrt1 22399K 1    356    0       
1A0165FA openwrt nQ A A A A 413     132         671+749  21 0a82c7c  fd70:1a01:65fa:6d39:dce1:20b6:1299:1f82 ---   ---       ---    257G   0    20     5
# en la salida anterior el nodo B se reconoce como openwrt1
# con identificador 7B037847
    
# tambien una descripcion mas completa con los detalles de los anuncios de cada nodo
bmx7 -c status originators descriptions tunnels
# que produce una salida muy larga
</pre>
</div>
La guía completa de comandos se puede ver en [https://github.com/bmx-routing/bmx7](https://github.com/bmx-routing/bmx7) o una descripcion mas corta con `bmx7 --verboseHelp`.

Como en las consultas anteriores vemos que el nodo B se ha dectectado, comprobamos que en el enrutador se hayan establecido rutas hacia él, por ejmplo con:

    :::bash
    ip -6 route
    # que muestra entre su salida que hay una ruta establecida hacia el nodo B
    fa99:1:b::/48 via fe80::ea94:f6ff:fe6b:80fa dev wlan0  metric 1024 
    fd70:7b03:7847:472a:414:9eee:2d98:3e14 via fe80::ea94:f6ff:fe6b:80fa dev wlan0  metric 1024 
    unreachable default dev lo  metric -1  error -128
    fa99:1:a::a dev wlan0  metric 256

En bmx7 los nodos configuran automáticamente una dirección IPv6 al azar y un indentificador único en la red, pero los anuncios de redes UHNA son únicos y eso suprime el riesgo de IP spoofing.

Ahora la comunicación entre el nodo A,B o una cantidad arbitraria de nodos es posible, podemos comprobar haciendo por ejemplo la prueba trazando rutas.

	:::bash
	traceroute -6 fa99:1:b::b

Que muestra que se puede llegar a esa direccion IP iendo por el nodo B.

    :::bash
    traceroute to fa99:1:b::b (fa99:1:b::b), 30 hops max, 16 byte packets
    1  fa99:1:b::b (fa99:1:b::b)  1.392 ms  1.581 ms  1.329 ms

    # usando ip para ver que ruta se sigue para alcanzar una IP
	ip route get fa99:1:b::b
	fa99:1:b::b from :: via fe80::ea94:f6ff:fe6b:80fa dev wlan0  src fc99:1:a::a  metric 1024 

### Modificaciones "en caliente" ###

En bmx7 no es obligatorio utilizar un archivo de configuración para modificar el comportamiento del protocolo. Cuando el demonio bmx7 esta ejecutándose con comandos se puede por ejemplo hacer que se anuncien bloques adicionales mediante UHNA.

    bmx7 -c u=fc01:1934:ffed::/64

Que haría que el nodo también anuncie el bloque `fc01:1934:ffed::/64`, de igual manera se puede hacer que se anuncien túneles, quitarlos, establecer póliticas para aceptar anuncios y distribuirlos, etc. Consulta la [guía oficial](https://github.com/bmx-routing/bmx7).

Con toda la flexibilidad que ofrece bmx7 ya tenemos construida una pequeña red en malla :)

## Referencias ##

1. [An evaluation of BMX6 for Community Wireless Networks](http://dsg.ac.upc.edu/sites/default/files/1569632801.pdf)
2. [Securely-Entrusted Multi-Topology Routing for
Community Networks](https://pdfs.semanticscholar.org/1752/f3710783f55784f8cf38a35cd5789bed8125.pdf)
