Tunnelling SSH via uPnP
The RaspPi that is going to act as the rsync server in the previous post needs to have SSH available from its internet connection. There are several ways we could arrange this. One obvious way would be to ensure that the DHCP server it acquires its IP address from gives it a static IP address, and then configure the firewall to forward some port (22 perhaps) to that IP.
The minor problem with this approach is that 3 parts of the system need to interact and all be configured. It would be better if only one thing needed configuring. In addition, at the off-site location for my server I'm not really in control of the DHCP or Firewall.
So in jumps uPnP. Normally we associated uPnP with media servers and DLNA. However there is another part of uPnP related to NAT and Firewall traversal. This is what we are interested in. There is a small package for RaspPi that provides this service (assuming that your router/firewall also supports this).
sudo apt-get install miniupnpc
With this installed you can now find out if your network has an IGDP-enabled feature. List the IGDP fowarding routes on your network.
root@backup-pi ~ # upnpc -l
upnpc : miniupnpc library test client. (c) 2006-2010 Thomas Bernard
Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
for more information.
List of UPNP devices found on the network :
desc: http://192.168.10.10:5000/rootDesc.xml
st: urn:schemas-upnp-org:device:InternetGatewayDevice:1
Found valid IGD : http://192.168.10.10:5000/ctl/IPConn
Local LAN ip address : 192.168.10.176
Connection Type : IP_Routed
Status : Connected, uptime=1520664s, LastConnectionError : ERROR_NONE
Time started : Sun Dec 21 18:27:44 2014
MaxBitRateDown : 8388608 bps MaxBitRateUp 4194304 bps
ExternalIPAddress = 192.168.0.3
0 UDP 10442->192.168.10.237:10442 'Azureus UPnP 10442 UDP' ''
1 TCP 10442->192.168.10.237:10442 'Azureus UPnP 10442 TCP' ''
2 TCP 2222->192.168.10.176:2222 'libminiupnpc' ''
3 UDP 59197->192.168.10.249:59197 'Teredo' ''
4 UDP 57138->192.168.10.249:57138 'Teredo' ''
GetGenericPortMappingEntry() returned 713 (SpecifiedArrayIndexInvalid)
To add a port forward to this machine simply execute something like
upnpc -r 2222 tcp
This requests a forward of TCP port 2222 to this machine (whatever its IP address is). Note the TCP (as opposed to UDP which could also be requested).
There is a limitation with uPnP that we need to be aware of. It is unlikely that the firewall will be able to forward priviledged TCP/UDP ports. Since SSH (22) is a priviledged port we are going to have to use something else. So now lets configure SSH to be more amenable to uPnP.
Edit /etc/ssh/sshd_config
to add the following
Port 2222
This tells the SSH daemon to also listen on port 2222 as well as 22.
Personally I also add the following to the end of the config. I want to ensure that all SSH connections coming from outside my network are authenticated using an SSH key.
# Generally DO NOT ALLOW passwords
PasswordAuthentication no
# Stop user 'pi' logging in using password
Match User pi
PasswordAuthentication no
# However from any where on the local network
# we do allow passwords to work
Match Address 192.168.10.0/24
PasswordAuthentication yes
This behaves as follows. Generally do not allow passwords as a way to login but keep looking down this list to see if anything changes this. If the user logging in is pi
(a well known user on a RaspPi) then do not allow login using a password and stop looking at configuration options. If you are still looking, then if the connection is from my local network (my DHCP server gives addresses in the 192.168.10.0
range) then allow passwords.
Having modified the SSH config you will need to ensure that it is loaded by the SSH daemon
sudo service ssh reload
Finally with SSH and uPnP configured to work correctly all we now need to ensure that if either the RaspPi or the firewall are rebooted the uPnP tunnel is still working. This can be done using cron
and recreating the tunnel every 5 mins or so. As root
execute crontab -e
and add the following line
*/5 * * * * /usr/bin/upnpc -r 2222 tcp >/dev/null 2>&1
This instructs cron to run the listed command every 5 mins.
With all this inplace you should now be able to SSH to the external IP address of your firewall on port 2222, and provided you have set up SSH keys (if you applied the security patch) you can connect to your RaspPi.