It might sound counterintuitive, but it’s actually possible. The reason I started looking into this was a news story about a malicious contributor to the xz package who attempted to include a backdoor.
I began wondering if there was a way to SSH into a server while blocking all incoming connections:
SSH port blocked
Server is connected to a relay (outbound)
It gets a message from the relay that someone is “knocking”
Opens the SSH port
Lives happily ever after
I then came across ZeroTier, which can create a virtual Ethernet device, effectively creating a virtual LAN. This virtual device behaves like a physical one on your local network. I became aware of Tailscale later, but its perceived complexity and my satisfaction with my existing zLAN setup have kept me from switching.
Setup¶
To get started, head over to https://
After installation, join your network using the network ID shown in the dashboard:
sudo zerotier-cli join ${NETWORK_ID}(On macOS, you can also use the tray icon).
Each new device will appear in your web dashboard under the network’s “Members” list. Approve (authorize) each device manually to allow it to join the network. Once approved, every node will have its own ZeroTier-assigned IP address. Personally, I prefer choosing an easy-to-remember subnet (avoiding public ones) and manually setting each member’s IP.
Isolating our zLAN via firewalld¶
Let’s assume we now have ZeroTier up and running.
At home, this setup is usually not an issue. The problem arises on my lab server, where multiple people are connected to the same subnet, some of whom are network security researchers...
The easiest way around this is to set up a firewall that blocks incoming connections from the physical Ethernet port using firewalld. Another alternative is to use a router to isolate the computer from the shared network (TODO).
I’ve just installed firewalld and want to configure it. The first thing to do is not to enable it until it’s properly set up; otherwise, you’ll lock yourself out of your server if you’re configuring it over SSH.
Since firewalld isn’t running yet, we use the offline command: firewalld-offline-cmd.
Run:
sudo firewalld-offline-cmd --list-all-zonesThis will show that there is a
public(default) zone with thesshservice, but no interface associated with it. At this point, all interfaces are associated with the defaultpubliczone.Let’s change the default zone to
drop:sudo firewalld-offline-cmd --set-default-zone=dropIf
firewalldis started now, all incoming connections will be dropped.Using
ip addrorifconfig, we can get the device name for our zLAN, e.g.,zeroeth.sudo firewalld-offline-cmd --zone=public --add-interface=zeroethMultiple interfaces can be added to the same zone.
--list-allshould now show the new interface in thepubliczone.Start the
firewalldservice.
ZeroTier doesn’t require any specific firewall rules, but we can make things easier by adding its service to the public zone.
The default service definitions are located in /usr/lib/firewalld/services/, and ZeroTier uses port 9993/udp.
sudo firewall-cmd --zone=public --add-service=zerotier --permanent
sudo firewall-cmd --reloadYou can now test SSH access via the LAN and via the zLAN.
ZeroTier Hacks¶
I’ll add here any hack worth noting to leverage ZeroTier. The obvious one is the ability to SSH into remote servers without having to set up a VPN or expose routers/computers to the internet. If you think this is overkill and that a public key and SSH encryption are enough, think again.
Remote Jupyter Server¶
Sometimes I run a Jupyter server on my lab computer and want to access it remotely. The server runs on ports 8080–8089 by default. I want to make that range accessible on my zLAN:
sudo firewall-cmd --permanent --new-service=jupyter
sudo firewall-cmd --permanent --service=jupyter --add-port=8080-8089/tcp
sudo firewall-cmd --permanent --service=jupyter --add-port=8080-8089/udp
sudo firewall-cmd --permanent --zone=public --add-service=jupyter
sudo firewall-cmd --reloadLet’s test this now by running:
jupyter notebook --no-browser --port=8080 --ip=0.0.0.0 --NotebookApp.token=''Then open $ZLAN_IP_ADDR:8080 on another computer that’s part of the zLAN. It will usually be port 8080 unless it’s already in use; check the stdout for the correct one. This makes the Jupyter server accessible to other computers.
To avoid typing this long command each time, run:
jupyter notebook --generate-configThis creates a config file at ~/.jupyter/jupyter_notebook_config.py.
Add the following settings:
c = get_config() # noqa
c.ServerApp.open_browser = False
c.ServerApp.password = ''
c.ServerApp.port = 8080
c.ServerApp.token = ''
c.ExtensionApp.open_browser = False
c.LabServerApp.open_browser = False
c.ServerApp.ip = '0.0.0.0'This is basically my workflow for a quick Jupyter server instance:
Quick SSH to my server:
ssh my-server(via pubkey to avoid typing passwords)Start a
tmuxsession (so the Jupyter server will remain open if we disconnect)Run the server
jupyter notebookfrom within my Python environmentOpen
$ZLAN_IP_ADDR:$PORTon my laptopVoila!
Test
Try running:
jupyter notebook --port=8090Open $ZLAN_IP_ADDR:8090
SSH Hopping¶
The goal here is to leverage our fixed IPs on the zLAN to do some SSH “hopping”: on the VPS/server, we keep an SSH connection open to a host “login.domain.com” which only accepts passwords and other verification tools. Then, we connect to “login.domain.com” from any device on the zLAN via the VPS’s open connection to bypass the verification process.
On the VPS
~/.ssh/config:
Host remote-node
HostName login.domain.com
User ayghri
ControlMaster auto
ControlPath ~/.ssh/cm-%r@%h:%p
ControlPersist yes # keep master daemon around
ServerAliveInterval 60
ServerAliveCountMax 3On the laptop
~/.ssh/config:
Host vps
Hostname 10.1.0.2
User ayghri
IdentityFile ~/.ssh/keys/vps-key
Host remote-via-vps
Hostname 10.1.0.2 # VPS' ZeroTier fixed IP
User ayghri # username
RequestTTY force
RemoteCommand ssh remote-node # run on VPS
IdentityFile ~/.ssh/keys/vps-key
IdentitiesOnly yesNow we have to SSH into the VPS and open a persistent SSH connection in the background, which will require going through the login.domain.com verification process:
ssh -fN remote-nodeNow we can either ssh vps from the laptop, then ssh remote-node, which should use the existing connection, or simply run ssh remote-via-vps directly from the laptop.
Merging zLAN with LAN¶
Check OpenWrt Router (Bpi-R3).