Skip to content

Layer 2 VPN’s using SSH

September 24, 2012


OpenSSH running on Linux provides the ability to create a VPN tunnel on-the-fly, which can be useful as a quick hack – it’s simple, stable, not the most efficient thing in the world – (tunneling TCP over TCP is generally considered to be a bad idea) – but way easier than trying to set up something like OpenVPN. For preliminary testing, anyway, you can’t beat it.

How it works:

When the tunnel is established, SSH creates a TAP (virtual ethernet tunnel) device on each computer. This link behaves more like a virtual wire than a NIC. As such, you can’t use it directly – you have to create a virtual bridge and add this TAP device to it, treating the bridge as the NIC.

If you created a tunnel and a bridge on either end of the link, and added only the TAP device to each bridge, you would essentially have a p2p link between the two machines, like a virtual crossover cable. By adding an additional physical NIC to the bridge on either side, you can join this virtual link to the physical network on the host. Since this is a layer 2 VPN, ARP traffic, dhcp, etc., can flow freely between physical networks as if they were one.


1) both computers must have root login enabled. (sorry – your credentials on both computers must allow you to create the TAP device). This means: on the system level, root has a password;

2) in the sshd_config file of the host that’s running the ssh daemon, the options PermitTunnel yes and PermitRootLogin yes are set;

3) ip forwarding is enabled in the kernel. Use the sysctl command to set this option: sysctl -w net.ipv4.ip_forwarding=1 ; also, add the line net.ipv4.ip_forwarding=1 to your /etc/sysctl.conf file for the setting to stick after you reboot. Do this on both computers;

4) You have installed the bridge-utils package, or otherwise have the brctl command available to you, on both computers.

Create the tunnel:

ssh -w 1:1 -o Tunnel=ethernet hostname

the -w option sets the name of the TAP device on either host (here, tap1 will be created on both ends).

the -o option is for specifying a config file option on the command line. We use Tunnel=ethernet to set up a layer 2 tunnel.

This form will keep the ssh session open in the foreground. If you’d like it to relinquish the shell after the tunnel is established, you can use the -f option to tell it to fork into the background. It needs a command to fork, though, so you can just use a dummy command such as true to get it to work. You could also use this functionality to set up the bridge on the remote end, but I’m not getting into that right now. So, it would look like this:

ssh -f -w 1:1 -o Tunnel=ethernet hostname true

Add TAP devices to a bridge:

brctl addbr br0; brctl addif tap1; ifconfig tap1 up; ifconfig br0 up

you run this on both hosts (Notice that I didn’t assign an IP). brctl is the command to use to manipulate bridge devices. brctl addbr adds the bridge br0, and the addif command joins the tap1 device to it.

Next up would be to add physical ethernet interfaces to the bridge device. How you’d want to do that will vary, so I’ll go over a couple of scenarios. The first scenario is where your VPN peers are on the same subnet (i.e., no routing between them), and the second scenario will be over the Internet.

Scenario 1:

You’re at your desk, which is on a particular subnet (say, and the weather’s really nice, so you want to sit outside and do your work on your laptop from there. The problem is, your wifi is on a totally different network ( You can, however, get wifi from your desk, and you have the ability to add devices to your wired subnet at will.


Grab another laptop and set it up at your desk as a bridge. Create an SSH VPN between your laptop and the one at your desk over the wireless 10.69 network, and bridge this tunnel onto the wired 10.0 network at your desk.

desk laptop:

eth0:, default gatway ( via eth0

wlan0, no gateway needed

outdoors laptop:

wlan0, default gw ( via wlan0

ssh -f -w 1:1 -o Tunnel=ethernet true

establish the tunnel, where the bridge computer is the server (although it doesn’t matter which one is the server/client)

brctl addbr br0 ; brctl addif br0 tap1; ifconfig br0 up; ifconfig tap1 up

on both computers.

brctl addif br0 eth0; dhclient -r eth0; dhclient br0

on the bridge computer – dhclient -r releases the IP address on eth0, because once bridged, you want to use br0 as the actual interface. The tunnel will stay up as long as you pull the same IP. Otherwise, you may need to configure it manually.

route del default; dhclient br0

on the outdoors laptop. route del default will delete the default route over the 10.69 network, because you want to use the tunneled VPN as your default route. You should then be pulling from the DHCP server on the 10.0 subnet, and your default route will be through the tunneled connection.

ping – success!

Scenario 2:

You’re working from home, and you may have a way to access your work PC remotely, but it’s not exactly ideal. (In my case, that would be an RDP session over Citrix ICA … )


Make sure that your computer at home is accessible from the Internet (at least the ssh port). You can use the same computer as above for this, too. The difference is that you SSH into your home computer from the bridge computer at your desk, rather than the other way around. What I actually did was that I grabbed an old PC, stuck a couple of nic’s in it, used one nic to connect to the Internet, and used the second one to bridge an actual lan at my house to the 10.0 network at my desk at work. The reason for that is – using my laptop alone, I found that I couldn’t actually use the tunneled link as my default gateway, since I had to maintain a route to the Internet for the tunnel to stay open in the first place. There’s probably a workaround, but I thought that having a dedicated lan setup would be more elegant anyway.

So I have a computer with 2 nic’s at home, one of which is connected to the internet with port 22 forwarded to it from the internet, and the other is connected to a layer 2 switch. What I’ve done is – I create the tunnel by remoting into my home network from the laptop at work. The configuration is the same on that end; at home, I want devices plugged into the switch on the second nic to be attached to my work network over the vpn. If that second interface is eth1, I’ll bring it up without an IP and bridge it to br0. If you wanted, you could give br0 an address (it would pull from the 10.0 DHCP server), but you don’t have to. Any computer that I plug into the switch on my desk at home will pull from the DHCP server at work. Cool stuff 🙂

If anyone reads this and would like to see examples for this second scenario, I’ll go back and add them in. Anyway, hope that helps.


From → Uncategorized

One Comment

Trackbacks & Pingbacks

  1. User-Based Routing | Some Blog

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: