VPN via SSH TAP interfaces

Useful to run the following on both local and remote, to get a sense of what's happening:

VM, where eth1 is connected to the network I want to make my RPi appear in:

Vagrantfile (based on using Parallels, rather than VirtualBox):

# -*- mode: ruby -*-
# vi: set ft=ruby :

BRIDGE_ADAPTORS=[
  "en0: Wi-Fi (AirPort)", # MacBook Pro (MacOS v10.15, Catalina), VirtualBox
  "en0",                  # MacBook Pro (MacOS v10.15, Catalina), Parallels
  "eno1",                 # Ubuntu 16.04 LTS
  # Add your OS's default here
  ]

Vagrant.configure("2") do |config|
  config.vm.box = "bento/ubuntu-20.04"
  config.vm.network "public_network", bridge: BRIDGE_ADAPTORS

  config.vm.provider "parallels" do |prl|
    # Cf. http://download.parallels.com/doc/pcs/html/Parallels_Cloud_Server_Command_Line_Reference_Guide/32912.htm
    prl.customize ["set", :id,
                   "--device-set", "net0", 
                   "--ipfilter", "no",
                   "--macfilter", "no",
                   "--preventpromisc", "no"]
    prl.customize ["set", :id,
                   "--device-set", "net1", 
                   "--ipfilter", "no",
                   "--macfilter", "no",
                   "--preventpromisc", "no"]
  end

  config.vm.provision "shell",
    privileged: true,
    inline: <<-SHELL
      # Secure Shell daemon configuration changes
      echo "PermitTunnel yes" >> /etc/ssh/sshd_config
      echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
      systemctl reload sshd

      # Root account is disabled by default (password begins with literal '!'),
      # so we'll change the password to re-enable the account
      usermod -p '*' root

      # Install GadgetPi's ~/.ssh/id_rsa.pub, so it can login as root without
      # requiring an operator
      umask 0077
      mkdir /root/.ssh
      echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCx963D3ErL6s9uWmSye1ZU+TCS4aDAJBbQI/NZLqg05EXnYVfXEPm2ZuStij4JjsIgdFbL+E73vd/alNgUBpe1YD73+oP9ndSdsAU/kXrx/zy0qCRWsi4fma6MmGIU0sYFuNvnwKsyjoFu0g5Y4SKQeD/0J7f+AmP4XOSnR2mhcFFE96wFYdq1UJanky0YI/oJcz2CRny5tO+iCjqm98BcvnEI/3vQOH4fOtffzW1SvqDobiQtP58POHd2NfRJo9ygVemCFqdvV9v17tvuhW0AxBZcBm1TZ9wb/oQnWvR8OvqO0XSYGZYuC+DERCSC+3dLSNL/LmoDDDdIjgHXTUNv root@raspberrypi
" >> /root/.ssh/authorized_keys

      # Enable acting as a router (forwarding packets)
      echo "" >> /etc/sysctl.conf  # In case the file does not end with a newline
      echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
      sysctl --load /etc/sysctl.conf
    SHELL

    config.vm.post_up_message = <<-EOF
      Run the following on this VM:

        ETH1_IP=192.168.167.100/24
        sudo ip link add br0 up type bridge     # Create a bridge
        sudo ip address add ${ETH1_IP} dev br0  # Copy the address and netmask of eth1
        sudo ip address flush dev eth1          # Remove eth1's addresses completely
        sudo ip link set eth1 master br0        # Attach eth1 to the bridge

      Run the following on the GadgetPi:
      
        REMOTE_HOST=192.168.167.237
        sudo ip link add br0 up type bridge
        sudo ip link set eth0 up master br0
        sudo ssh \\
            -o PermitLocalCommand=yes \\
            -o "LocalCommand=ip link set tap5 up master br0" \\
            -o Tunnel=ethernet \\
            -w 5:5 \\
            -t \\
            root@${REMOTE_HOST} \\
            "ip link set tap5 up master br0"
    EOF
end

Debugging

I found tshark - Dump and analyze network traffic useful, as it can capture ethernet frames to a file (such as /vagrant/tshark) which you can then load into the Wireshark GUI after the fact.