Seguimos con la configuración de nuestra red privada virtual con Raspberry Pi. Si recordáis, en un artículo anterior hablé de sobre cómo convertir una Raspberry Pi 2B en un servidor OpenVPN con Pi-Hole cómo servidor DNS. En esta ocasión, vamos a utilizar nuestra Raspberry Pi como repetidor wifi utilizando solamente el adaptador integrado. Además, y opcionalmente, crearemos un bridge entre este punto de acceso y la interfaz eth0., es decir, algo como esto:
Así que, sin más dilación, comencemos.
Configurando Raspberry Pi como repetidor Wifi
Para esta configuración se asume lo siguiente:
- Tenemos una Raspberry Pi 3B
- Con Raspbian Strectch instalado
- Y la configuración inicial hecha (Acceso a internet, locales, etc..)
En primer lugar, y antes de empezar, actualizaremos el SO:
1 | sudo apt-get update && sudo apt-get upgrade && sudo apt-get dist-upgrade |
1. Cambiando de networking a systemd-networkd
En primer lugar desactivaremos el sistema de red por defecto y pasaremos a usar systemd-networkd. Este servicio, pensado para redes virtuales nos permitirá crear interfaces virtuales, bridges, etc… sin software adicional.
Además, nos permitirá controlar el orden de arranque de interfaces y servicios, que, en esta configuración, es crítico. Debe ser como sigue:
- Crear la interfaz virtual para el punto de acceso
- Iniciar el daemon hostapd del punto de acceso
- Iniciar wpa_supplicant para la conexión wifi en wlan0
- Iniciar openVPN para establecer el tunel tun0
Para hacerlo, en una consola con privilegios elevados, sudo -sE ,introducimos los siguientes comandos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #Activamos el journal permanente mkdir -p /var/log/journal systemd-tmpfiles --create --prefix /var/log/journal #Instalamos hostapd y lo desactivamos apt install rng-tools hostapd systemctl stop hostapd #Desactivamos el servicio networking y dhcp systemctl mask networking.service systemctl mask dhcpcd.service mv /etc/network/interfaces /etc/network/interfaces~ sed -i '1i resolvconf=NO' /etc/resolvconf.conf #Activamos el sistema networking de systemd systemctl enable systemd-networkd.service systemctl enable systemd-resolved.service ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf |
2. Configuración Hostapd para punto de acceso
Para confiugrar el punto de acceso editamos el archivo hostapd.conf, nano /etc/hostapd/hostapd.conf y añadimos lo siguiente:
1 2 3 4 5 6 7 8 9 10 11 | interface=ap0 ssid=RPiNet country_code=ES hw_mode=g channel=1 auth_algs=1 wpa=2 wpa_passphrase=contraseñaSecreta wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP rsn_pairwise=CCMP |
Modificaremos los ssid , country_code y wpa_passphrase según nuestras preferencias. Es importante además, establecer el channel al canal que tendrá la wifi a la que nos conectaremos en wlan0.
A continuación, editaremos el archivo nano /etc/default/hostapd y modifcaremos la siguiente línea:
1 | DAEMON_CONF="etc/hostapd/hostapd.conf" |
Además, en el archivo nano /etc/init.d/hostapd comentaremos las siguientes líneas:
1 2 3 | ## Should-Start: $network #DAEMON_CONF= |
La línea Should-Start ha de tener dos almohadillas (##) delante. Además, indicaremos dónde está el archivo de configuración de hostapd.
Finalmente, añadiremos la interfaz del punto de acceso, ap0, al hostapd.service. Para ello ejecutamos el comando systemctl edit hostapd.service y en el editor introducimos lo siguiente:
1 2 3 4 5 6 | [Unit] Wants=wpa_supplicant@wlan0.service [Service] ExecStartPre=/sbin/iw dev wlan0 interface add ap0 type __ap ExecStopPost=-/sbin/iw dev ap0 del |
3. Configuración de wpa_supplicant para la conexión Wifi
Para ello abriremos un editor nano /etc/wpa_supplicant/wpa_supplicant-wlan0.conf y, configuramos la interfaz.
1 2 3 4 5 6 7 8 | country=ES ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid="SSID" psk="PASSWORD" } |
Una vez creado el archivo, le damos los permisos pertinentes. A continuación desactivamos wpa_supplicant par proceder a reactivarlo en la interfaz wlan0:
1 2 3 | chmod 600 /etc/wpa_supplicant/wpa_supplicant-wlan0.conf systemctl disable wpa_supplicant.service systemctl enable wpa_supplicant@wlan0.service |
Una vez hecho extendemos el servicio wpa_supplicant,enlazándolo al servicio hostapd. Ademas, haremos masquerading en dicha interfaz.
Ejecutamos systemctl edit wpa_supplicant@wlan0.service y en el editor que se abrirá ponemos:
1 2 3 4 5 6 7 | [Unit] BindsTo=hostapd.service After=hostapd.service [Service] ExecStartPost=/sbin/iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE ExecStopPost=-/sbin/iptables -t nat -D POSTROUTING -o wlan0 -j MASQUERADE |
3.1 Configurando las interfaz wlan0
1 2 3 4 5 6 7 8 9 10 | [Match] Name=wlan0 [Network] IPForward=yes # En caso de necesitar IP estática, descomenta las siguientes líneas y configura DHCP=yes #Address=192.168.10.60/24 #Gateway=192.168.10.1 # Si queréis configurar unos servidores DNS descomentad la siguiente línea #DNS=192.168.10.10 8.8.8.8 |
3.2 Configurando Raspberry Pi como repetidor wifi
1 2 3 4 5 | [Match] Name=ap0 [Network] Address=192.168.4.1/24 DHCPServer=yes |
Reiniciamos la Raspberry Pi y ya la tendríamos funcionando cómo repetidor wifi.
Configurando el bridge ap0-eth0
Si habéis llegado hasta aquí es que queréis que vuestra Raspberry se conecte a un punto de acceso mediante la interfaz wlan0 y que «comparta» esa conexión en las interfaces ap0 y eth0 en la misma red.
Pues vamos a ello. Al igual que antes, comenzamos elevando privilegios con sudo -sE .
4. Configurar hostapd para bridge
Este paso es muy sencillo. Simplemente añadimos la línea bridge=br0 al final del archivo /etc/hostapd/hostapd.conf creado anteriormente con el siguiente comando:
1 | echo 'bridge=br0' >> /etc/hostapd/hostapd.conf |
5. Configurar wpa_supplicant para bridge
Vamos a extender el servicio wpa_supplicant, systemctl edit wpa_supplicant@wlan0.service , que creamos anteriormente para que quede como se ve a continuación:
1 2 3 4 5 6 7 8 9 10 | [Unit] BindsTo=hostapd.service After=hostapd.service Wants=ap-bring-up.service Before=ap-bring-up.service [Service] ExecStartPost=/sbin/iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE ExecStopPost=-/sbin/iptables -t nat -D POSTROUTING -o wlan0 -j MASQUERADE ExecStopPost=-/bin/ip link set ap0 up |
Como se puede obserbar, requerimos que el punto de acceso está activado antes de iniciar el servicio hostapd. Este es el orden requerido, cómo hemos visto anteriormente.
6. Servicio del punto de acceso en la interfaz virtual
En el punto anterior se hace referencia al servicio ap-bring-up.service, pasaremos a crearlo con systemctl --force edit ap-bring-up.service :
1 2 3 4 5 6 7 8 | [Unit] Description=Bring up wifi interface ap0 Requisite=hostapd.service [Service] Type=oneshot ExecStart=/lib/systemd/systemd-networkd-wait-online --interface=wlan0 --timeout=60 --quiet ExecStartPost=/bin/ip link set ap0 up |
7. Configurando las interfaces estáticas br0 y eth0
Por último pasamos a crear la interfaz bridge br0. Crearemos también la redeth0 y la añadiremos al bridge. No es necesario crear la interfaz ap0 puesto que se crea automáticamente y se vincula al bridge mediante hostapd.
Creamos la interfaz br0 con el comando nano /etc/systemd/network/02-br0.netdev :
1 2 3 | [NetDev] Name=br0 Kind=bridge |
Configuramos la red eth0 con nano /etc/systemd/network/04-eth0.network :
1 2 3 4 | [Match] Name=eth0 [Network] Bridge=br0 |
Por último, configuramos la red br0 mediante el comando /etc/systemd/network/16-br0_up.network :
1 2 3 4 5 6 7 8 | [Match] Name=br0 [Network] Address=192.168.4.1/24 DHCPServer=yes # Optional: if you want your own DNS server, set it here (example) #[DHCPServer] #DNS=192.168.4.10 8.8.8.8 |
Reiniciamos y ya tenemos nuestra Raspberry Pi como punto de acceso para compartir una conexión wifi con sólo el adaptador integrado. Además, esta conexión se comparte también mediante Ethernet gracias al bridge que hemos creado.
Conexión a servidor OpenVPN
Por último, vamos a conectarnos a nuestro servidor VPN mediante OpenVPN, de este modo, estableceríamos un tunel privado entre la Wifi a la que nos conectemos y el servidor OpenVPN que hayamos configurado.
Comenzamos instalando OpenVPN
1 | sudo apt-get install openvpn |
8. Configuración de la conexión
La configuración es de lo mas sencilla. Comenzamos obteniendo un archivo .ovpn con PiVPN cómo se explicó en el artículo anterior. Una vez lo tengamos, lo copiamos en la carpeta /etc/openvpn y lo renombramos:
1 | mv /etc/openvpn/XXXXX.ovpn /etc/openvpn/XXXXX.conf |
En caso de que hayamos establecido una contraseña para la clave privada deberemos crear un archivo /etc/openvpn/XXXXX.pass en el que escribiremos la contraseña en una sola línea. Además, editaremos el archivo de configuración nano /etc/openvpn/XXXXX.conf para añadir lo siguiente antes de la definición de certificados:
1 | askpass /etc/openvpn/XXXXX.pass |
9. Conexión automática al arracar
Para que la conexión a nuestra VPN se establezca automáticamente al arrancar la Raspberry Pi necesitamos descomentar la siguiente línea en /etc/default/openvpn :
1 | AUTOSTART="all" |
Está opción intentará establecer una conexión por cada archivo .conf en /etc/openvpn .
10. Redirigiendo el tráfico a través de la VPN
Para redirigir el tráfico a través de nuestra VPN (cuando esté disponible) vamos a extender el servicio openVPN del siguiente modo systemctl edit openvpn.service :
1 2 3 4 5 6 7 8 9 10 | [Unit] BindsTo=wpa_supplicant@wlan0.service After=wpa_supplicant@wlan0.service [Service] Type=oneshot ExecStartPost=/sbin/iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE ExecStartPost=/sbin/iptables -A INPUT -i tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT ExecStopPost=-/sbin/iptables -t nat -D POSTROUTING -o tun0 -j MASQUERADE ExecStopPost=-/sbin/iptables -D INPUT -i tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT |
Problemas encontrados
Uno de los problemas con esta configuración, Raspberry pi como repetidor Wifi utilizando sólo la interfaz integrada, es que el comportamiento de systemd.networkd con un AP virtual tiene ciertos errores. El principal es que no va a propagar los servidores DNS a los clientes conectados mediante DHCP.
Si utilizamos OpenVPN para la conexión esto no supone un problema puesto que la resolución DNS se hará en el servidor VPN al final del tunel. Sin embargo, si sólo utilizamos el punto de acceso podemos encontrarnos con conexión sin internet al no tener servidor DNS para resolver los nombres.
Si no, es necesario sustituir el servidor DHCP integrado por dnsmasq. Para ello comenzamos instalando el susodicho paquete y una vez instalado, detenemos el servicio.
1 2 | apt-get install dnsmasq systemctl stop dnsmasq.service |
A continuación, lo configuraremos creando el siguiente archivo de configuración nano /etc/dnsmasq.conf y añadiendo:
1 2 3 4 5 | interface=br0 dhcp-range=192.168.4.128,192.168.4.164,255.255.255.0,24h #Descomenta la siguiente línea para utilizar servidores DNS distintos de los que facilita el router #server=8.8.8.8 #server=8.8.4.4 |
Debemos desactivar tambien resolvconf, puesto que usamos systemd-resolved para obtener los servidores DNS. Para ello modificamos la siguiente línea (quitando el comentario): nano /etc/default/dnsmasq
1 | IGNORE_RESOLVCONF=yes |
Por último, comentaremos la línea DHCPServer=yes en el archivo /etc/systemd/network/16-br0_up.network
Ahora sólo queda iniciar de nuevo el servicio systemctl start dnsmasq que a partir de ahora se encargá de repatir las IPs.
Dicho esto ponemos fin a esta guía. Espero que os haya servido de ayuda, y recordad que no está escrita en piedra y puede no funcionar para vosotros. Sea cómo sea creo que os servirá como punto de partida para vuestras propias configuraciones.
Actualización 13/05/2019
Si no os funciona esto y en el arranque veis un mensaje del estilo [Skipping] Ordering cycle found esto se debe a una actualización de hostapd y sus dependencias.
El problema es que ahora hostapd ha de ejecutarse después de network.target algo que no es posible porque nuestro wpa_supplicant ha de ejecutarse después de hostapd y antes de network.target, por lo que tenemos un ciclo de dependencias que nunca se cumplirá.
Para solucionarlo ejecutamos el comando
sudo systemctl --full edit hostapd.service
Y comentamos la siguiente línea:
#After=network.target
Reiniciamos y tendríamos el problema solucionado.