The initial goal of this project is to use the raspberry pi in place of my Wireless Range Extender and then going from 3 wireless networks (2.4ghz, 2.4ghz extended, 5ghz) at home to only one (5ghz). This way I'm reducing the exposition to radio waves for the whole familly at home.
Ok, enough drama for now, let's go technical. π
To make your Wireless Bridge, you'll need to have few hours as free time and the following hardware:
- Raspberry Pi 2/3B/B+/4B
- One network cable
- One HDMI cable (or TFT screen)
- One Micro SD card (4GB should be suffisent but I used a 8GB one to be sure to haveenough place when the OS is growing due to updates)
- For Raspberry Pi 2
- For Raspberry Pi 3B/3B+ (for using a TFT screen and fix the wireless network issues)
- For Raspberry Pi 3B/3B+/4B (latest version but contains a wireless network bug and don't load TFT screen drivers)
- For Raspberry 4B (latest version / not tested yet)
- The provided files (systemd service and launch script)
For the Raspberry Pi 3B/3B+/4B you can even use 64Bit images instead of Hard-Float images (
ARMHF
) but during my testing the performances appeared to be less better than the Hard-Float images and the device temperature was higher.Also found that there are less packages built for 64Bit ARM images / platforms so you should take this into account before these images but if you still want to give them a try, here are the links:
- http://cdimage.ubuntu.com/ubuntu/releases/18.04.4/release/ubuntu-18.04.4-preinstalled-server-arm64+raspi3.img.xz
- http://cdimage.ubuntu.com/ubuntu/releases/18.04.4/release/ubuntu-18.04.4-preinstalled-server-arm64+raspi4.img.xz
The images above has not been tested yet.
Just write the downloaded image on the SD card and follow this procedure.
- Power your screen on
- Plug the HDMI cable
- Plug the network cable
- Put the Micro SD card
- Plug the power cable
- Wait the initial boot to finish
- Define your password (you will asked to change the default credentials)
- Default credentials:
- user:
ubuntu
- pass:
ubuntu
- user:
- Default credentials:
One important thing you might notice is that
sudo
is not asking for password, you can change this behavior by changing the value in/etc/sudoers
file.
This should not be required as the main partition will be resized on the first boot with all the remaining size on your SD card.
In case the auto-resize has failed, you can follow the procedure explained here: https://raspberrypi.stackexchange.com/questions/499/how-can-i-resize-my-root-partition
Now check your interfaces names with ip link show
or iwconfig
. You'll need them to create the configuration required by netplan
.
So, edit the file /etc/netplan/your-config-file.yaml
and add or change the following:
# This file is generated from information provided by
# the datasource. Changes to it will not persist across an instance.
# To disable cloud-init's network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
version: 2
renderer: networkd
# Renderer can be 'networkd' or 'NetworkManager'
ethernets:
eth0:
optional: true
dhcp4: false
wifis:
wlan0:
optional: true
dhcp4: true
access-points:
"YOUR-SSID-NAME":
password: "YOUR-PASSWORD"
# uncomment the line below if you're using a Microsoft DHCP Server
#dhcp-identifier: mac
Try to run the test again while commenting out the lines
Once done, test, generate and apply the config that way:
- Testing:
sudo netplan --debug try
(continue even if successful) - Generate:
sudo netplan --debug generate
(will give you more details in case of issues with the previous command) - Apply:
sudo netplan --debug apply
(if no issues during the previous commands, you can start to enjoy π)
Define the wireless country code!!
Note that it is only required when using
NetworkManager
asrenderer
in thenetplan
config file.I've forgotten to do that at first try and trust me I wasted around 5 hours before thinking about that...
Edit the file /etc/default/crda
and change it that way:
# Define your country code here as explained above or in this format if not explained:
# ISO/IEC 3166-1 alpha2 country code
REGDOMAIN=CH
Then save the file.
Now that your network config is done, the first thing to do is to update the whole system. Nothing really difficult, just run these commands:
sudo apt update && sudo apt dist-upgrade
If case of outdated package definitions, replace the command by this one:
sudo apt update --fix-missing -y && sudo apt dist-upgrade
If you prefer a more automated way, here is the one-liner
I'm using:
sudo apt update --fix-missing -y && sudo apt dist-upgrade -y && sudo apt autoremove --purge -y
You will need to install some packages which are not included by default in Ubuntu Server 18.04.
sudo apt install wireless-tools wpasupplicant openssh-server
Note that
wpasupplicant
andopenssh-server
might be already installed.
Now install the required bridging packages:
sudo apt install parprouted dhcp-helper
If you want to relay the
mDNS
protocol, add theavahi-daemon
package to the chain.
Enable DHCP relay: /etc/default/dhcp-helper
# relay dhcp requests as broadcast to wlan0
DHCPHELPER_OPTS="-b wlan0"
If you have installed the avahi-daemon
paackage, you will have to edit the /etc/avahi/avahi-daemon.conf
file to enable mDNS relaying:
[reflector]
enable-reflector=yes
You'll have to create an extra systemd
service file and place it in /lib/systemd/system/
.
Create the service file and name it /lib/systemd/system/arp-bridge.service
then put this content:
[Unit]
Description=ARP Bridge over Wireless Interface
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/lib/systemd/system/set-arp-routing start
ExecStop=/lib/systemd/system/set-arp-routing stop
ExecReload=/lib/systemd/system/set-arp-routing restart
[Install]
WantedBy=multi-user.target
Create the starting script and name it /lib/systemd/system/set-arp-routing
then put this content:
#!/bin/bash
## ARP Routing Management Script
## Made by Jiab77 <[email protected]>
## Config
ETHERNET_IFACE=eth0
WIRELESS_IFACE=wlan0
KEYBOARD_LAYOUT=ch
DISABLE_POWER_MGMT=true
## Help
if [ $# -eq 0 ]; then
echo -e "\nUsage: $0 action [start|stop|restart|status]\n"
exit
fi
## Functions
function start_service {
## Setup system forwarding
echo -e "\nEnable IP forwarding..."
echo 1 > /proc/sys/net/ipv4/ip_forward
## Uncomment lines below if you don't want to use parprouted.
#echo "Enable ARP forwarding"
# Comment for all interfaces
#echo 1 > /proc/sys/net/ipv4/conf/${WIRELESS_IFACE}/proxy_arp
# Uncomment for all interfaces
#echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp
## Fix the 'eth0' interface that don't want to mount at boot on 3b+
## Uncomment this part if the 'eth0' interface is not mounted at boot
#/usr/sbin/netplan apply
## A little sleep
sleep 2
## Assign address
echo "Cloning IP from ${WIRELESS_IFACE} to ${ETHERNET_IFACE}..."
/sbin/ip addr add $(/sbin/ip addr show $WIRELESS_IFACE | perl -wne 'm|^\s+inet (.*)/| && print $1')/32 dev $ETHERNET_IFACE
## Uncomment lines below in case you're encountering the same issues
#echo "Removing bad APIPA IP from ${ETHERNET_IFACE}"
#/sbin/ip addr del $(/sbin/ip addr show $ETHERNET_IFACE | perl -wne 'm|^\s+inet (169.254.*)/| && print $1')/16 dev $ETHERNET_IFACE
#echo "Removing bad APIPA route from ${ETHERNET_IFACE}"
#/sbin/ip route del 169.254.0.0/16 dev $ETHERNET_IFACE
## Make sure that the eth0 interface is up
echo "Setting up lan interface..."
/sbin/ip link set $ETHERNET_IFACE up
## Setup ARP forwarding
echo "Starting paraprouted..."
/usr/bin/killall -KILL parprouted 2> /dev/null
/usr/sbin/parprouted $ETHERNET_IFACE $WIRELESS_IFACE
## Reloading DHCP Relay
echo "Start / Reload DHCP Relay..."
/bin/systemctl restart dhcp-helper
## A little sleep
sleep 2
## Refresh local ARP cache
echo "Refresh local ARP cache..."
/sbin/ip -s -s neigh flush all
}
function stop_service {
## Stop ARP forwarding
echo -e "\nKilling paraprouted..."
/usr/bin/killall -KILL parprouted 2> /dev/null
## Stop DHCP Relay
echo "Stoping DHCP Relay..."
/bin/systemctl stop dhcp-helper
## Remove assigned address
echo "Removing attached IP to ${ETHERNET_IFACE}..."
/sbin/ip addr del $(/sbin/ip addr show $WIRELESS_IFACE | perl -wne 'm|^\s+inet (.*)/| && print $1')/32 dev $ETHERNET_IFACE
## Stop ethernet interface
echo "Setting lan interface down..."
/sbin/ip link set $ETHERNET_IFACE down
## Disable system forwarding
echo "Disable IP forwarding..."
echo 0 > /proc/sys/net/ipv4/ip_forward
## Refresh local ARP cache
echo "Refresh local ARP cache..."
/sbin/ip -s -s neigh flush all
}
function service_status {
IP_FORWARDING_STATUS=$(cat /proc/sys/net/ipv4/ip_forward)
ARP_ROUTING_PROC=$(ps aux | grep -v grep | grep -i parprouted)
## Display network interfaces config
echo -e "\nNetwork interfaces:\n"
/sbin/ip -c a
## Display IP forwarding status
if [[ $IP_FORWARDING_STATUS == '0' ]]; then
echo -e "\nIP forwarding: disabled"
else
echo -e "\nIP forwarding: enabled"
fi
## Display ARP routing process
echo -e "\nARP Routing process:\n$ARP_ROUTING_PROC"
## Display ARP table
echo -e "\nARP table:\n"
/usr/sbin/arp -vn
## Display DHCP Helper status
echo -e "\nDHCP Relay status:\n"
/bin/systemctl status dhcp-helper
}
function generic_actions {
## Disable wireless power management
## Set the variable to true if your wireless speed is too low
if [[ $DISABLE_POWER_MGMT == true ]]; then
/sbin/iwconfig $WIRELESS_IFACE power off
fi
## Not related to network at all but useful for me,
## as my keyboard does not have an English layout.
## Set the variable KEYBOARD_LAYOUT to your layout is not in English too.
if [[ $KEYBOARD_LAYOUT != '' ]]; then
/usr/bin/loadkeys $KEYBOARD_LAYOUT
fi
}
## Actions (Generic)
generic_actions
## Actions (Service)
case "$1" in
'start')
start_service
;;
'stop')
stop_service
;;
'restart')
stop_service
sleep 5
start_service
;;
'status')
service_status
;;
*)
echo -e "\nInvalid argument.\n"
;;
esac
## End Process
set starting script as executable:
sudo chmod -v u+x /lib/systemd/system/set-arp-routing
Now save everything and check if everything is correctly setup:
# Reload systemd config
sudo systemctl daemon-reload
# Enable and start the service
sudo systemctl enable --now arp-bridge.service
# Display systemd service status
systemctl wpa_supplicant.service status arp-bridge.service
# Display custom service status
sudo /lib/systemd/system/set-arp-routing status
Try to ping any host you know and if that works then you can reboot to verify if all the proces is mounted correctly at boot time.
sudo reboot
Watch the boot process to check if you got some issues...
If you don't and everything is working for you, trust me, you're ... lucky π.
Now log into the bridge using SSH
if you're working remotely now or normally from screen. π
Before to follow the next intructions, be aware that this procedure won't work on the latest Ubuntu Server images for Raspberry Pi. I've test with models 3B/3B+/4B, all failed to load the driver with the latest image.
The only solution was to use the image Ubuntu Server 18.04.3.
Copy the DTBO
and/or DTB
files from your TFT screen driver in the /boot/overlay
folder of the micro sd card.
Edit the file /boot/config.txt
and add this content:
# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
disable_overscan=1
# uncomment if hdmi display is not detected and composite is being output
hdmi_force_hotplug=1
# Enable required hardware interfaces
dtparam=spi=on
dtparam=i2c_arm=on
# Enable audio (loads snd_bcm2835)
dtparam=audio=on
# Enable serial console
enable_uart=1
# Load the TFT screen driver
dtoverlay=tft35a:rotate=90
These settings might differ depending on your TFT screen model.
The given settings are for the model tft35a.
Then change the boot command line file /boot/cmdline.txt
with this content:
net.ifnames=0 dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 fsck.repair=yes fsck.mode=auto root=LABEL="writable" rootfstype=ext4 elevator=deadline rootwait fbcon=map:10 fbcon=font:ProFont6x11 logo.nologo
Now you can reboot and normally the TFT screen should light up during the boot and the HDMI display will not be used anymore.
If you need to go back on the HDMI display without having to remove everything, just comment the line loading your driver in the file /boot/config.txt
that way:
# Load the TFT screen driver
#dtoverlay=tft35a:rotate=90
On the next reboot, the TFT screen will not be used and everything will going through the HDMI display.
After upgrading the whole system, the boot files has been upgraded too and most of them will be renamed. The correspondance with the modified files are the following:
/boot/config.txt
->/boot/usercfg.txt
/boot/cmdline.txt
->/boot/nobtcmd.txt
Note that when the system is running the
/boot
folder is mapped to/boot/firmware
.
In this section, I'll explain how to setup the autologin
+ screen
+ wavemon
.
The output has been truncated for privacy reasons.
It's very simple to setup the autologin
:
# Check the getty path
which getty
# Edit the getty service
sudo systemctl edit getty@tty1
Add the following content:
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin [username] --noclear %I $TERM
Do the following changes:
- Replace
/sbin/getty
by the path given with thewhich
command - Replace
[username]
by the username you want to autologin
You can find more details here: https://wiki.archlinux.org/index.php/Getty#Automatic_login_to_virtual_console
Normally screen
should be already installed on your systemd but if not, just run the following command:
sudo apt install screen
To display the wireless network activity on the TFT screen, I'm using wavemon
. You can install it that way:
sudo apt install wavemon
Now that all dependencies are installed, you can create a small launch script that will called when the session will automatically open:
#!/bin/bash
# Create an attached Screen session usable from SSH
screen -S physical bash -c '/usr/bin/wavemon'
Save the script as wireless-mon.sh
and make it executable: chmod -v +x wireless-mon.sh
.
Once done, add the following content in the .bashrc
file to call it when the session is started:
# Load screen + wavemon
if [ $(tty) == /dev/tty1 ]; then
for I in {5..1} ; do echo "Initializing monitor in $I seconds..." ; sleep 1 ; done
~/wireless-mon.sh
fi
Now you can reboot to see the result π
If everything has worked correctly, you should have a running screen
session created that display the wavemon
output with some nice wireless network info π€
To connect on that session, run the following commands:
# Connect via SSH on the remote host
ssh user@host
# List existing screen sessions
screen -ls
# Connect on the existing session
screen -x
# To disconnect without killing the screen session
[Ctrl+a] d
You can find more details here: https://linoxide.com/linux-how-to/screen-remote-ssh/
To make sure that everything is running correctly and having more info in case of issues, create a log file for the WPA
process.
Open the file /lib/systemd/system/wpa_supplicant.service
and this -dd -f /tmp/wpa.log
to the end of the ExecStart
line:
# ExecStart=/sbin/wpa_supplicant -u -s -O /run/wpa_supplicant
ExecStart=/sbin/wpa_supplicant -u -s -O /run/wpa_supplicant -dd -f /tmp/wpa.log
This does not seems to work with
netplan
, you might need to kill the existing process and reload it with the given parameters above.Do this only in case you have wireless network issues or for debugging purpose.
I've set to
/tmp/wpa.log
to avoid useless storage space consumption.
If you want to test the speed of your wireless bridge, you can use the script speedtest-cli
that way:
python3 <(curl -Ss https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py) --secure
The
--secure
argument is to useHTTPS
insteadHTTP
during the test, feel free to remove it.
I've made a small script that you can use:
#!/bin/bash
python3 <(curl -Ss https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py) --secure $*
Save it as speedtest.sh
and make it executable with chmod -v u+x speedtest.sh
.
Then you can run it that way:
# Get help
./speedtest.sh --help
# Get server list
./speedtest.sh --list
# Use a specific server
./speedtest.sh --server <server-id>
Sometimes the LAN
interface is not started, the following might solve this issue:
# Re-Apply networking configuration
sudo netplan --debug apply
# Or manually set the network interface up
sudo ip link set eth0 up
Change
eth0
by your interface name
During my debugging process I used these commands to help me to solve all encountered issues:
sudo loadkeys keyboard_country_code
sudo lshw
ifconfig
iwconfig
iw list
iw dev
iw phy
sudo iw dev wlan0 scan sched_stop
sudo iw dev wlan0 scan
ip link show
ip a
ip route
sudo rfkill list
sudo rfkill unblock wifi
networkctl
journalctl -b
journalctl -f
dmesg
dmesg -w
sudo wpa_cli status
sudo wpa_cli interface_list
sudo netstat -s | egrep -i 'loss|retran'
host -a google.com
host -a ubuntu.com
iwlist
iwlist wlan0
sudo iwlist wlan0 scan
sudo iwlist wlan0 scan | grep ESSID
locate wpa
sudo ip link set wlan0 down
sudo ip link set wlan0 up
sudo iw reg get
sudo iw reg set CH
sudo nmcli radio wifi on
sudo nmtui
nmcli dev show wlan0
nmcli device wifi
nmcli device wifi rescan
sudo iwlist wlan0 scan
arp -avn
sudo su -c 'echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp'
sudo su -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'
sudo sysctl -a | grep forward
sudo sysctl -a | grep proxy
sudo sysctl -w net.ipv4.ip_forward=1
sudo sysctl -w net.ipv4.conf.all.proxy_arp=1
During my research, I've found this debugging script: https://github.com/UbuntuForums/wireless-info/raw/master/wireless-info
Use it as follow:
wget https://github.com/UbuntuForums/wireless-info/raw/master/wireless-info && chmod +x wireless-info && ./wireless-info
Reply 'no' to not upload results outside
Show the report:
less wireless-info.txt
It was another hard lesson that I've learned during this project / gist, never plug several bridges on the same switch, it will just create massive TPC/UDP retransmission and ARP flood... π
Well... I must tell you that I've passed around 3 days in reading, testing, debugging and getting crazy then finaly make it working π .
And even more to understand why my not all of my
DHCP
requests were not relayed to the my mainDHCP
Server on the router... But after many days of testing and research I was finally able to find why. More details here https://twitter.com/Jiab77/status/1107535593741922304
I really hope that you'll be able to make the whole process working on your side.
Feel free to comment this gist for improvements or if you're having troubles π.
I'd like to give a big thanks to someone who helped me to solve the screen
issues I got, Klimi from the Hack+ Telegram group.
You can reach me on Twitter by using @Jiab77.
During my research it was really difficult to find up-to-date, clean and working documentation so I had to grab and mix many of them to write this gist. (no specific order)
- https://wiki.ubuntu.com/ARM/RaspberryPi
- http://cdimage.ubuntu.com/ubuntu/releases/18.04.3/release/
- https://ubuntuforums.org/showthread.php?t=2274207
- https://wiki.debian.org/BridgeNetworkConnectionsProxyArp
- https://github.com/balena-io-playground/balena-bridge/blob/master/start.sh
- https://www.freedesktop.org/software/systemd/man/systemd.exec.html
- https://www.freedesktop.org/software/systemd/man/systemd.service.html
- https://unix.stackexchange.com/questions/348450confused-by-execstartpre-entries-in-systemd-unit-file
- https://netplan.io/faq#use-pre-up-post-up-etc-hook-scripts
- https://hk.saowen.com/a873f9d84ef3c295c9ea73174de8758f972d73e32434d6c332ddd72bd2a4e4441
- https://unix.stackexchange.com/questions/126009cause-a-script-to-execute-after-networking-has-started
- https://websiteforstudents.com/configure-static-ip-addresses-on-ubuntu-18-04-beta/
- https://medium.com/@benmorel/creating-a-linux-service-with-systemd-611b5c8b91d6
- https://bbs.archlinux.org/viewtopic.php?id=230785
- https://www.tecmint.com/create-new-service-units-in-systemd/
- https://unix.stackexchange.com/questions/319267systemd-how-to-make-a-systemd-service-start-after-network-fully-connected/319330
- https://superuser.com/questions/544399how-do-you-make-a-systemd-service-as-the-last-service-on-boot
- https://www.cyberciti.biz/faq/howto-set-sysctl-variables/
- https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_MRG/1.3/htmlRealtime_Tuning_Guidesect-Realtime_Tuning_Guide-General_System_Tuning-Setting_persistent_tuning_parametershtml
- https://linuxize.com/post/how-to-change-hostname-on-ubuntu-18-04/
- https://cloudinit.readthedocs.io/en/latest/topics/network-config.html
- https://pimylifeup.com/raspberry-pi-wifi-bridge/
- https://medium.com/a-swift-misadventurehow-to-setup-your-raspberry-pi-2-3-with-ubuntu-16-04-without-cables-headlessly-9e3eaad2c01
- https://askubuntu.com/questions/1045389ubuntu-18-on-raspberry-pi-3b-stuck-on-networking-service-after-converting-the-o
- https://askubuntu.com/questions/1071517trying-to-install-18-04-classic-on-pi-3-b-close-but-not-quite-there?rq=1
- https://raspberrypi.stackexchange.com/questions/499how-can-i-resize-my-root-partition
- https://community.arubanetworks.com/t5/Controller-Based-WLANsDHCP-packet-flow-with-bootp-flag-set-to-broadcast-vs-unicast/ta-p/425012
- https://superuser.com/questions/472594/dhcp-broadcast-flag/472607#472607
- https://www.ietf.org/rfc/rfc2131.txt
- https://wiki.archlinux.org/index.php/Getty#Automatic_login_to_virtual_console
- https://linoxide.com/linux-how-to/screen-remote-ssh/
Made with β€οΈ and A LOT of β!! by @jiab77
In case you wanted used files directly, check the revisions. I just removed them for better indexing... π