SSH is widely known as the tool to use to remotely connect to other computers and run commands on them. However, what if you need to run commands on a computer that you don't have the ability to currently connect to? Well, that becomes substantially more difficult, and it helps to plan in advance for how you will restore your access to remotely connect. I happened to find myself in such a situation, years ago, and setup such a plan. I mostly forgot about it until recently, when it was needed, and I had to remember what I had setup, and how to use it, in order to restore the access I needed. Read on for the background behind the need, how I setup SSH to handle access restoration, the problems I ran into when I finally had to use it, and how I worked around them.
Like many technically-oriented people, I have other not-so-technically-oriented people in my extended family that I provide technical support for. In this particular case, I have a VPN between my home network and the home network of the other family member. This VPN allows for both remote troubleshooting and for backing up each network to the other for disaster recovery.
I originally set up the VPN between our home networks in late 2005, after the introduction of ipsec.conf in OpenBSD 3.8, which allowed for very easily setting up an IPSEC VPN between two networks. In 2021, I converted the VPN from using IPSEC to using Wireguard, using the instructions in wg(4), but that's not really important to the story at hand.
What is important to the story at hand is that this other home network is behind an DSL modem, and the DSL modem would occasionally have its configuration reset. The default DSL modem configuration did not allow for the VPN to work, because it used network address translation on all devices behind it. The only way to get the VPN to work would be to put the DSL modem in passthrough mode, where a particular device behind the modem (an OpenBSD firewall in this case) would be assigned the public IP address. Once the OpenBSD firewall was assigned the public IP address, things were fine, as I could remotely access the firewall. However, if the DSL modem configuration did get reset, I needed to be able to get access to configure the DSL modem remotely, otherwise the VPN wouldn't work.
For about the first 10 years of this arrangement, if there were problems with the DSL modem configuration, I would just wait until I was on-site and could take care of it. However, when it happened in 2015, I decided to try to setup a way to remotely fix things without having to come on-site, using SSH. It turns out that things were mostly smooth after that, with the DSL modem configuration not resetting for quite a few years. However, earlier this month, the DSL modem configuration was reset, and I wasn't going to be on-site in the near future, so I had to remember the remote access I setup in 2015 and how to use it.
It took me a while to remember how to use the remote access I had setup, since it had been over 6 years by this point. At first, I only remembered that I had setup remote access to handle this very case, but had completely forgot how to use it. However, remember that one reason I setup this VPN was for backups. I decided to look at the backups and see if there was something there that could help remind me. Thankfully, I found what I was looking for, in a file named setup_tunnel.bat
(it was designed to run on a Windows system), which had the following contents:
plink -R 22022:10.1.2.1:22 -N -i reverse_ssh.ppk -P 18989 reverse_ssh@dyndns.mynetwork
First, this is using plink
, which is PuTTY's command line equivalent of ssh(1). Let's break down what each of these flags do:
-R 22022:10.1.2.1:22
: When connecting, setup a remote port forward from port 22022 on the remote host to port 22 on 10.1.2.1 on the local network.-N
: Don't start a shell or command, since this will only be used for the remote port forward.-i reverse_ssh.ppk
: Use the given private key when connecting.-P 18989
: Connect to port 18989.reverse_ssh@dyndns.mynetwork
: Connect to host dyndns.mynetwork
using username reverse_ssh
.So the main point of this command is that the user in the other network can run a command that will connect to a computer in my network, setting up a port forward so that I can connect through that computer to the firewall on the other network. Once I have that access, I can get access to the DSL modem and modify the configuration.
This command almost worked great. There was only one, minor issue, which was that I had forgotten the password for reverse_ssh.ppk
. I had a copy of the reverse_ssh.ppk
file, as well as the OpenSSH private key on which it was based, but while I tried many passwords, I was unable to remember the correct one.
However, luckily I had installed also installed PuTTYgen on the other machine, which can be used to generate a new keypair. It had been quite a few years since I had used PuTTYgen, but I was able to Google to find screenshots of the PuTTYgen user interface, and was able to walk the user through generating a new keypair, saving the private key over reverse_ssh.ppk
, and sending me the public key via email. I took the public key that they sent me, and modified ~reverse_ssh/.ssh/authorized_keys
on the computer they were connecting to to use the new public key.
After that change, I had them try running setup_tunnel.bat
again. Unfortunately, the results were still unsuccessful. I had an idea of what the problem might be, so I checked /var/log/authlog
on the computer they were connecting to, and found the following lines:
userauth_pubkey: key type ssh-rsa not in PubkeyAcceptedAlgorithms
Connection closed by authenticating user reverse_ssh 123.55.110.49 port 52935 [preauth]
This issue comes from a change in OpenSSH 8.8 to tighten security and drop the older, less secure ssh-rsa
public key algorithm. The PuTTYgen that generated the public key was from 2015, and was still using this older algorithm. So I opened up sshd_config on the computer they were connecting to, and added:
PubkeyAcceptedAlgorithms +ssh-rsa
As an aside, there was already code to limit what the reverse_ssh
user could do in sshd_config
:
Match User reverse_ssh
PubkeyAuthentication yes
ForceCommand /bin/false
Anyway, after modifying sshd_config
and restarting sshd
, the setup_tunnel.bat
file worked, and the user could successfully remotely connect. Then I had to use the reverse tunnel to setup access to the DSL modem webpage, so I could modify the configuration. The first step was setting up ssh access to the firewall at the remote site. I was able to accomplish that by modifying ~/.ssh/config
and adding a entry to connect through the reverse tunnel:
Host via_reverse_tunnel
Hostname localhost
Port 22022
TCPKeepAlive yes
This connects to 22022
on localhost, which the reverse tunnel has forwarded to port 22 on the firewall of the remote network. This worked, successfully restoring my remote access to the firewall at the remote site.
From there I had to poke around to figure out where the DSL modem configuration website was hosted. Thankfully, one of my first guesses, 192.168.1.254
, worked. I quickly added the following to the via_reverse_tunnel
entry in ~/.ssh/config
:
LocalForward *:8080 192.168.1.254:80
After that change, I disconnected and reconnected the SSH connection. Then I could navigate to http://localhost:8080 on that machine, and get access to the DSL modem configuration. From there it was a simple matter of enabling passthrough mode on the modem, choosing the correct passthrough machine (the OpenBSD firewall), then restarting dhcpleased via doas rcctl restart dhcpleased
to pick up the public IP address from the DSL modem. Immediately after that, the Wireguard VPN started working again, fully restoring remote access.
My main lesson learned from this experience is to better document my system configurations, and test them more frequently, so that they will work when needed. I've handled the better documentation by writing this post. Time will tell if I follow through on the more frequent testing. Hopefully this post will help some other people see how SSH can be used to solve problems of this nature.