Skip to main content
8 of 9
Updated General Setup to run with systemd-resolved and tested Static setup with Raspbian Buster
Ingo
  • 43.1k
  • 20
  • 87
  • 207

Proxy arp is a way to build a pseudo bridge that is working on OSI layer 3 but it behaves like a real layer 2 bridge. So it is a good way to workaround the lack of WDS support on Raspberry Pi. Here is a way to set it up. In general I followed the tutorial (2). Have a look at it for the background.

Example Setup

 ┌─proxy arp─┐ UPLINK wired V V wifi wan laptop <─────────> (eth0)RPi(wlan0) <~.~.~.~.> hotspot <---> INTERNET \ \ (dhcp from hotspot) (dhcp from hotspot) 

I will present two setups. One that is only static but simpler. It is configured one time on startup and does not respect changes on its interfaces. You have to reboot then. It is good for static use cases, for example to connect a printer. The other setup is a bit more complex but it will monitor connection changes on its interfaces. It is usable on mobile RasPis that will connect to different WiFi networks and wired connections on the fly.

Tested with
Raspbian Buster Lite 2019-09-26 on a Raspberry Pi 4B updated at 2020-02-05. Updates done with sudo apt update && sudo apt full-upgrade && sudo reboot.
Here you can find the last tested revision for previous Raspbian versions.


♦ Static configuration of proxy arp

First do **♦ General Setup** (look at the end).

Then follow this setup. parprouted runs as a daemon but has no systemd unit installed. So we will make it and enable also promiscous mode:

rpi ~# systemctl edit --full --force parprouted.service 

In the empty editor insert these statements, save them and quit the editor:

[Unit] Description=proxy arp routing service Documentation=https://raspberrypi.stackexchange.com/q/88954/79866 [Service] Type=forking PIDFile=/run/parprouted.pid # Restart until wlan0 gained carrier Restart=on-failure RestartSec=5 TimeoutStartSec=30 ExecStartPre=/lib/systemd/systemd-networkd-wait-online --interface=wlan0 --timeout=6 --quiet ExecStartPre=/bin/echo 'systemd-networkd-wait-online: wlan0 is online' # clone the dhcp-allocated IP to eth0 so dhcp-helper will relay for the correct subnet ExecStartPre=/bin/bash -c '/sbin/ip addr add $(/sbin/ip -4 -br addr show wlan0 | /bin/grep -Po "\\d+\\.\\d+\\.\\d+\\.\\d+")/32 dev eth0' ExecStartPre=/sbin/ip link set dev eth0 up ExecStartPre=/sbin/ip link set wlan0 promisc on # v minus sign ExecStart=-/usr/sbin/parprouted eth0 wlan0 ExecStopPost=/sbin/ip link set wlan0 promisc off ExecStopPost=/sbin/ip link set dev eth0 down ExecStopPost=/bin/bash -c '/sbin/ip addr del $(/sbin/ip -4 -br addr show eth0 | /bin/grep -Po "\\d+\\.\\d+\\.\\d+\\.\\d+")/32 dev eth0' [Install] [email protected] 

Enable the service:

rpi ~# systemctl enable parprouted.service 

Reboot.
That's it.


♦ Dynamic configuration of proxy arp with monitoring interfaces

Because we will monitor the state of the inerfaces wlan0 and eth0 we have to use a program that will report changes. For this I have made the **ifplug.service**.

So first Make ifplugd available again since Raspbian Stretch.

If you have tested the ifplug.service and it works,

then do ♦ General Setup.

After that configure the eth0 interface with this file:

rpi ~# cat > /etc/systemd/network/04-eth.network <<EOF [Match] Name=eth0 EOF 

As action file for the ifplug.service use this /etc/ifplugs/ifplugs.action script:

#!/bin/bash # redirect all output into a logfile for debug #exec 1>> /tmp/ifplug-debug.log 2>&1 INTERFACE="$1" EVENT="$2" IPADDR='' get_ipaddr () { if [ "$EVENT" = "down" ]; then IPADDR=$(/sbin/ip -4 -br addr show $INTERFACE | /bin/grep -Po "\d+\.\d+\.\d+\.\d+") return 0 fi # check 10 times with 1 sec delay if ip address is available for ((i=10; i>0; i--)); do IPADDR=$(/sbin/ip -4 -br addr show $INTERFACE | /bin/grep -Po "\d+\.\d+\.\d+\.\d+") [ $? -eq 0 ] && break /bin/sleep 1 done } case "$INTERFACE" in eth0) case "$EVENT" in up) # clone ip address from wlan0 and start parprouted IPADDR=$(/sbin/ip -4 -br addr show wlan0 | /bin/grep -Po "\d+\.\d+\.\d+\.\d+") if [ -n "$IPADDR" ]; then /sbin/ip addr add $IPADDR/32 dev eth0 /usr/sbin/parprouted eth0 wlan0 fi ;; down) # stop parprouted /usr/bin/killall -q parprouted /sbin/ip -4 addr flush dev eth0 ;; *) >&2 echo empty or undefined event for "$INTERFACE": \""$EVENT"\" exit 1 ;; esac ;; wlan0) case "$EVENT" in up) # clone ip address from wlan0 and start parprouted get_ipaddr if [ -n "$IPADDR" ]; then /sbin/ip addr add $IPADDR/32 dev eth0 /sbin/ip link set wlan0 promisc on /usr/sbin/parprouted eth0 wlan0 fi ;; down) # stop parprouted /usr/bin/killall -q parprouted /sbin/ip link set wlan0 promisc off /sbin/ip -4 addr flush dev eth0 ;; *) >&2 echo empty or undefined event for "$INTERFACE": \""$EVENT"\" exit 1 ;; esac ;; *) >&2 echo empty or unknown interface: \""$INTERFACE"\" exit 1 ;; esac 

Reboot.
That's it.

You can follow actions with:

rpi ~$ journalctl --follow | grep "ifplugd\|parprouted" 

♦ General Setup

Install helpers and setup systemd-networkd

I will use *systemd-networkd* for reasons so first we have to switch over to it. For detailed information look at [**(1)**](https://raspberrypi.stackexchange.com/a/78788/79866). Here only in short. Execute these commands:
# install helpers rpi ~$ sudo -Es rpi ~# apt install parprouted dhcp-helper rpi ~# systemctl stop dhcp-helper rpi ~# systemctl enable dhcp-helper # deinstall classic networking rpi ~# apt --autoremove purge ifupdown dhcpcd5 isc-dhcp-client isc-dhcp-common rpi ~# rm -r /etc/network /etc/dhcp # setup systemd-resolved rpi ~# apt --autoremove purge avahi-daemon rpi ~# apt install libnss-resolve rpi ~# systemctl enable systemd-resolved.service rpi ~# ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf # enable systemd-networkd rpi ~# systemctl enable systemd-networkd.service 

Configure wpa_supplicant

To configure *wpa_supplicant* create this file with your settings for `country=`, `ssid=` and `psk=`. You can just copy and paste this in one block to your command line beginning with `cat` and including EOF (delimiter EOF will not get part of the file):
rpi ~# cat > /etc/wpa_supplicant/wpa_supplicant-wlan0.conf <<EOF ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 country=DE network={ ssid="TestNet" key_mgmt=WPA-PSK proto=RSN WPA psk="verySecretPassword" } EOF rpi ~# chmod 600 /etc/wpa_supplicant/wpa_supplicant-wlan0.conf rpi ~# systemctl disable wpa_supplicant.service rpi ~# systemctl enable [email protected] 

To configure the wlan0 interface create this file:

rpi ~# cat > /etc/systemd/network/08-wlan0.network <<EOF [Match] Name=wlan0 [Network] IPForward=yes DHCP=yes # for a static ip address comment DHCP=yes # and uncomment next 3 lines with your settings #Address=192.168.50.2/24 #Gateway=192.168.50.1 #DNS=84.200.69.80 1.1.1.1 EOF 

Setup helpers

We have installed *dhcp-helper*, a proxy to get ip addresses from the wifi network, and *parprouted* that manages **proxy arp**.

Enable DHCP relay in /etc/default/dhcp-helper:

# relay dhcp requests as broadcast to wlan0 DHCPHELPER_OPTS="-b wlan0" 

End of General Setup. Go back.


references:
[1] Howto migrate from networking to systemd-networkd with dynamic failover
[2] Bridging Network Connections with Proxy ARP

Ingo
  • 43.1k
  • 20
  • 87
  • 207