Using the schematic below as an example, the requirement is to run a bespoke application on the laptop that sends TCP data on port 6000 to the remote Linux servers C & E.
There is no network route between Server A and Server C or E.
The solution was achieved using multiple SSH Tunnels.
This design is based on the earlier 19.07 software, I did try upgrading to a newer version but the performance was affected. There are differences in the firewall configuration that you will require to check if using current software.
The initial task was to get OpenVPN running on the router running OpenWRT, this was carried out using this straightforward to follow process:
Once OpenVPN was configured and a port forward from the broadband router was added (UDP port 1194) it was possible to connect using PuTTY to Server A over SSH.
It is possible to log into Server B & D over SSH from Server A, however from A you can't reach C or E. From B you can SSH to C and from D you can SSH to E. This is where an SSH tunnel can provide a working path end to end, two tunnels are required, the first from Server A to B or D, the second tunnel runs from B to C or D to E.
Server A has two network interfaces, eth0 is on the main 10.0.0.0 subnet, eth1 is connected to the 192.168.1.0 subnet provided by the broadband router.
The OpenWRT router needs to know what to do with packets sent from the laptop to Server C or E. This requires static routes to be added to the network configuration that have the eth1 ip address (192.168.1.10) as their gateway. The route can be added either in the web interface or by editing the /etc/config/network file.
Running the laptop application with the static routes the port 6000 data is now present on the eth1 interface and can be shown using tcpdump.
In order to get the packets from eth1 to eth0 on the main Linux server it is necessary to add the following entries into the firewall table:
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 6000 -j REDIRECT --to-port 6001 -d 10.3.0.1
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 6000 -j REDIRECT --to-port 6001 -d 10.5.0.1
It was also necessary to enable the forwarding between the eth0 and eth1 interfaces for port 6000 using the following:
iptables -A FORWARD -i eth1 -o eth0 -p tcp -m tcp --dport 6000 -j ACCEPT
Anyone paying attention will notice that the final destination port in the PREROUTING table is 6001, this is due to port 6000 already being in use on Servers B & D, it is therefore necessary to move the data to a different port.
An SSH tunnel from Server A to B is started using the following command:
ssh -v -4 root@10.2.0.1 -L 0.0.0.0:6001:10.2.0.1:6001
Once running any packets from the laptop to UDP port 6000 will be present on Server B and can be shown using tcpdump. A similar tunnel can be setup for the Server D connection using:
ssh -v -4 root@10.4.0.1 -L 0.0.0.0:6001:10.4.0.1:6001
Now that packets have reached Server B & D it is necessary to create a second tunnel to reach the final destination servers C & E. The changed 6001 port also requires to be moved back to the original port 6000. The SSH tunnels in server B & D are started using:
ssh -tt -4 root@10.3.0.1 -L 0.0.0.0:6001:10.3.0.1:6000
Or
ssh -tt -4 root@10.5.0.1 -L 0.0.0.0:6001:10.5.0.1:6000
With both tunnels setup, the client application running on the laptop can access the server application running on Server C & E. Any server that can be connected to over SSH should be able to be routed as part of the tunnel. To drop the second tunnel it is necessary to use "Ctrl-C"
I don't think there was any other way to meet this requirement but would appreciate input from others on the setup.
In the actual system this has been implemented in there is at least 50 remote servers that need connected to from the laptop. To make the ssh tunnel setup easier I have created a bash script that takes the Server name as an argument ($1)
Here is the script:
#!/bin/bash
echo "FALSE" > count.txt
awk '/'$1'/{print}' /root/sitelist.txt | while read server_name ip_address ip_host
do
echo "TRUE" > count.txt
ssh -tt -4 root@$ip_host -L 0.0.0.0:6001:$ip_host:6000
done
if grep -q "FALSE" count.txt; then
echo "Unable to match supplied parameter with name '$1' in sitelist.txt file"
fi