epoch1970
Posts: 3109
Joined: Thu May 05, 2016 9:33 am
Location: Paris, France

Pi 3 wifi client ethernet LAN bridging with OpenVPN

Fri Feb 02, 2018 7:18 pm

Ethernet bridging from wifi clients (aka STAs) is not supported per WiFi specifications. In general ethernet bridging over wifi is reserved to access points.

This post describes a LAN bridge built with a Pi 3 wifi client and an OpenVPN tunnel. This setup is for private use only.

Code: Select all

++ House +--------------------+  ++ Shed +------------+
|             +--------+      |  |      +-----+       |
|             |Router  | )))) WiFi (((( |RPI 3|       |
|             |WiFi AP |      |  |      |Ovpn |       |
|             |DHCP    |      |  | .150 +--+--+       |
| 192.168.1.1 +----+---+      |  |  bridge | Ethernet |
|                  | Ethernet |  |         |          |
|          +-----------+      |  |         |          |
|   bridge |           |      |  |         |          |
|       +--+--+     +--+--+   |  |      +--+--+       |
|       |PC A |     |PC B |   |  |      |PC C |       |
|       |Ovpn | .20 +-----+   |  |  .30 +-----+       |
|   .10 +-----+               |  |                    |
+-----------------------------+  +--------------------+
"PC C" is on the same network as all other machines, although it sits behind a Pi 3 wifi client connected to an Access Point. "PC C" receives all broadcasts from the LAN and an IP address from the DHCP server in the router.
On each side of the wifi Access Point, a computer runs OpenVPN bridged to its ethernet port ("PC A", "RPI 3".)
"PC A" is the OpenVPN server, it runs in the background and waits for the client to connect. "RPI 3" is the OpenVPN client, it tries to reach the server over wifi as soon as possible.

Installing on "PC A" and "RPI 3"
  • "PC A" happens to be a Debian Jessie (virtual) machine; DHCP client over ethernet.
  • "RPI 3" runs a stock Raspbian Stretch Lite installation; DHCP client over wifi.

    To install the required software I simply ran on both machines:

    Code: Select all

    sudo apt-get update && sudo apt-get upgrade
    sudo apt-get install bridge-utils openvpn
Server-side configuration on "PC A"
This covers networking and OpenVPN, please adapt to your OS.
  • Make sure the OpenVPN server starts at boot.
  • Custom /etc/network/interfaces file:

    Code: Select all

    # This file describes the network interfaces available on your system
    # and how to activate them. For more information, see interfaces(5).
    
    source /etc/network/interfaces.d/*
    
    # The loopback network interface
    auto lo
    iface lo inet loopback
    
    # Bridge - Same MAC as eth0 
    auto br0
    iface br0 inet dhcp
    pre-up ip tuntap add dev tap0 mode tap
    pre-up ip link set dev tap0 address fe:01:ae:eb:12:34
    pre-up ip link set dev tap0 up
    pre-up ip link set dev eth0 up
    bridge-stp on
    bridge-bridgeprio 65534
    bridge-maxwait 2
    bridge-fd 2
    bridge-ports eth0 tap0
    # IP address used by the OpenVPN client and server.
    post-up ip link add name ovpn0 type dummy
    post-up ip addr add 10.10.10.10/32 dev ovpn0
    Note:
    • I use MAC-based IP reservations with DHCP; Setting tap0 to use a MAC address starting with "fe:" guarantees the bridge br0 will adopt the MAC address of eth0. So the DHCP server will give to br0 the address previously configured for eth0.
    • If OpenVPN listens on the IP address of br0, clients like "PC C" won't be able to ping "PC A" (not sure why.) Using an IP on a free network (10.10.10.10/32) works around the issue.
  • OpenVPN config file /etc/openvpn/bridge-svr.conf:

    Code: Select all

    # Server config
    local 10.10.10.10 # Our interface address
    dev tap0
    ifconfig-nowarn
    passtos
    fast-io
    
    persist-tun
    ping-timer-rem
    keepalive 10 30
    
    cipher none  # We rely on WPA
    
    mute 10
    verb 1
    writepid /run/openvpn/bridge-srv.pid
    Note: To minimize overhead and simplify installation the OpenVPN tunnel is without authentication and encryption (and runs in "p2p" mode). It is assumed that the wifi link is encrypted. Do not use this setup over a public or unencrypted link.
Client-side configuration on "RPI 3"
This covers the complete setup for a current install of Raspbian Lite.
  • Make sure the OpenVPN server starts at boot by editing file /etc/default/openvpn to read:

    Code: Select all

    AUTOSTART="all"
  • Edit file /etc/dhcpcd.conf so that the first lines read...

    Code: Select all

    # A sample configuration for dhcpcd.
    # See dhcpcd.conf(5) for details.
    
    denyinterfaces br0 tap0 eth0
    ... and leave the rest of the file unchanged.
  • To obtain a static route to the OpenVPN server, create file /lib/dhcpcd/dhcpcd-hooks/40-ovpn-static-route:

    Code: Select all

    # Route to the local OpenVPN server
    if [ "$interface" = "wlan0" ]; then
     ip route add 10.10.10.10/32 dev "$interface"
    fi
  • Custom /etc/network/interfaces file:

    Code: Select all

    # interfaces(5) file used by ifup(8) and ifdown(8)
    
    # Please note that this file is written to be used with dhcpcd
    # For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'
    
    # Include files from /etc/network/interfaces.d:
    source-directory /etc/network/interfaces.d
    
    # Transparent bridge - No IP address
    auto br0
    iface br0 inet manual
    pre-up ip tuntap add dev tap0 mode tap
    post-down ip tuntap del dev tap0 mode tap
    pre-up ip link set dev tap0 up
    pre-up ip link set dev eth0 up
    bridge-stp on
    bridge-bridgeprio 65535
    bridge-maxwait 2
    bridge-fd 2
    bridge-ports eth0 tap0
    # Route to the OpenVPN server: see
    # /lib/dhcpcd/dhcpcd-hooks/40-ovpn-static-route
  • OpenVPN config file /etc/openvpn/bridge-clt.conf:

    Code: Select all

    # Client config
    remote 10.10.10.10 # Address defined at server side
    dev tap0
    ifconfig-nowarn
    passtos
    fast-io
    
    resolv-retry infinite
    persist-tun
    keepalive 10 30
    
    cipher none  # We rely on WPA
    
    mute 10
    verb 1
    writepid /run/openvpn/bridge-clt.pid
    Note: If the wifi link is less than very good or is not reliable, the LAN bridge won't work so well... Client and server exchange pings every 10 seconds and try to restart the tunnel if pings fail for 30 seconds.
Test and run
Reboot both machines and hopefully they will come back online.
  • This is what you could see on the server, "PC A"...

    Code: Select all

    $ sudo brctl show br0
    $ brctl show br0
    bridge name   bridge id          STP enabled   interfaces
    br0           fffe.525400138d13  yes           eth0
                                                   tap0
    
    $ netstat -4an | grep 1194
    udp        0      0 10.10.10.10:1194        0.0.0.0:*
    
    $ ip -4 addr show
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
    4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        inet 192.168.1.10/24 brd 192.168.1.255 scope global br0
           valid_lft forever preferred_lft forever
    6: ovpn0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default 
        inet 10.10.10.10/32 scope global ovpn0
           valid_lft forever preferred_lft forever
    
    $ ip route show
    default via 192.168.1.1 dev br0 
    192.168.1.0/24 dev br0  proto kernel  scope link  src 192.168.1.10
  • ... and on the client "RPI 3":

    Code: Select all

    $ lsb_release -a
    No LSB modules are available.
    Distributor ID:	Raspbian
    Description:	Raspbian GNU/Linux 9.3 (stretch)
    Release:	9.3
    Codename:	stretch
    
    $ uname -a
    Linux raspberrypi 4.9.59-v7+ #1047 SMP Sun Oct 29 12:19:23 GMT 2017 armv7l GNU/Linux
    
    $ dpkg-query --show openvpn
    openvpn   2.4.0-6+deb9u2
    
    $ brctl show br0
    bridge name   bridge id          STP enabled   interfaces
    br0           ffff.5a41791f6e6e  yes           eth0
                                                   tap0
    
    $ netstat -4an | grep 1194
    udp        0      0 0.0.0.0:1194            0.0.0.0:*
    
    $ ip -4 addr show
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
    3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
        inet 192.168.1.150/24 brd 192.168.1.255 scope global wlan0
           valid_lft forever preferred_lft forever
    
    $ ip route show
    default via 192.168.1.1 dev wlan0 src 192.168.1.150 metric 303 
    10.10.10.10 dev wlan0 scope link 
    192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.150 metric 303
Now connect a machine to the Pi's ethernet port and start it. It should be able to acquire a DHCP address and see all other machines on the main network. You can add a switch behind the Pi if you wish to connect multiple machines.

I've tested this setup a little bit. YMMV according to wifi link quality, but for me reliability and latency were adequate for a few clients behind the Pi to stream music and video concurrently.
On the Pi, system load seems reasonable and CPU temperature does not rise. The formula should also work with a full Raspbian Desktop on the Pi (Not tested.)
Be sure to use an adequate PSU as this setup taxes both wifi and ethernet network adapters at the same time.

HTH and have fun.
"S'il n'y a pas de solution, c'est qu'il n'y a pas de problème." Les Shadoks, J. Rouxel

Return to “Networking and servers”