2

I've got a server with 2 network interfaces.

Due to a restrictive NAT firewall, it establishes an SSH tunnel to a server on the internet:

ssh -fNTMS "/tmp/tunnel.socket" host;

ssh -S "/tmp/tunnel.socket" -O forward -R "0:localhost:22" placeholder

Normally it connects via a wired 1GB ethernet connection (eth0); but it's unreliable, as it's in an office where people move stuff around, and the cable "falls out" (unfortunately I can't use glue).

It also has a mobile 4G internet connection (eth1), which is slower, and more expensive.

To ensure the tunnel is still working, I'm periodically using the -O check command:

ssh -S "/tmp/tunnel.socket" -O check placeholder
  Master running (pid=3430)

echo $?
  0

If this -O check fails, the socket will be closed (via -O exit), and a new SSH connection will be established.

If the failure was due to the eth0 network cable "falling out", then Linux will automatically use eth1.

This works really well.

But, when eth0 is back up again, I'd like to switch back to it.

So I'm thinking, when running -O check, I could see if the tunnel is currently using eth1 (the point of this question), and if eth0 is back, re-connect.


Routing information:

ip route
  default via 192.168.1.1 dev eth0 proto dhcp src 192.168.1.225 metric 100 
  default via 192.168.2.1 dev eth1 proto dhcp src 192.168.2.241 metric 200

Note how eth1 has a metric of 200, so eth0 gets priority when it's working.

I can't find anything in /proc/3430/

I can list connections with lsof:

lsof -ai -p 3430 -n -P

  COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
  ssh     3430 craig    3u  IPv4  69362      0t0  TCP 192.168.1.225:43878->1.1.1.1:22 (ESTABLISHED)

And netstat -tpln does not show interfaces when listing sockets.

12
  • 1
    How does the fall back happen? I don't get it. You mean your ssh is connected, eth0 goes down and automagically the traffic goes over 4G with no external intervention? May 20, 2020 at 14:27
  • Just normal routing, if eth0 is down, the default route Linux uses changes. As in, the check command fails, so that connection is lost, then it a new connection is established (imagine these examples in a while true). May 20, 2020 at 14:30
  • 1
    You could use -b' with ssh` or assign metrics to the routes. But you will have to add more information. I suggest you add at least the fallback script, and the current routing table would not hurt. You might ask, how does this answer my question? Well, for example, depending on the situation, the source address might be enough to know the interface being used. But it's not clear (to me at least) whether NAT is between you and the interfaces or between the interfaces and the remote server. May 20, 2020 at 14:50
  • 1
    In the end, can your problem be decoupled from SSH and be turned into: "how can I know the interface currently in use to reach 1.1.1.1"? Or would that be "the considered already established connection" (not that it would not matter a lot if there was a change: it wouldn't work anymore) rather than the "planned possible connection"?
    – A.B
    May 20, 2020 at 15:52
  • 1
    You should consider a wireguard tunnel if the peer end supports it. Automatic roaming built-in. Whatever's inside the tunnel will hardly notice the interface changed.
    – A.B
    May 20, 2020 at 18:22

2 Answers 2

1

A possible solution (I'm using it) is to create a new interface on each side. Then connect them via the -w switch of ssh.

First you should setup the two local default routes with the right metrics. Whenever there is a change (eth0 up or down) you will lose the connection, but that's not a problem (read on).

Create tun devices on each server and let the user access them. Something like (you have to swap the addresses for the other side):

sudo ip tuntap add dev tun3 mode tun user myuser group mygroup
sudo ifconfig tun3 10.9.0.1 pointopoint 10.9.0.2 netmask 255.255.255.255

Then, if you do

ssh -w3:3 myuser@remote_host

You will have those two interfaces connected via a ssh tunnel and you will be able to ping them. If you lose the connection, no problem, the tun devices will wait until you restablish it and resume.

From this moment on, you can connect the remote host over a "stable" link that will use eth0 or 4G as needed, but keeping the addresses (10.9.0.1/10.9.0.2).

Instead of ssh I suggest you use autossh (and keys) with the -M flag (monitor). It will detect that the link is lost and reconnect.

That's really close to a full-fledged VPN (you can apply routing, policies, firewall, ... to the tun interfaces), but it works on the good old ssh you know so well.

3
  • Thanks, that's a really nice approach, I'll give it a try, as well as the wireguard suggestion from a.b... hope you don't mind, but I don't think I can mark this as the accepted answer, as my question is fundamentally flawed, and the answer is simply "the tunnel uses the default interface with the lowest metric, it's not tired to a single interface". May 21, 2020 at 18:51
  • It's pretty common for the answer to be a bit off, once you tell the actual problem your facing the solutions come anyway. That's what the site is for. So, if you end up using it ... feel free to accept it anyway ;) as a solution to the problem if not the answer to the flawed question. May 21, 2020 at 21:35
  • nice idea. its not working in WSL ubuntu18.04 unfortunately due to the limited network stack
    – U.V.
    Apr 7, 2022 at 13:41
0

I'm being stupid... the tunnel uses the default interface with the lowest metric, it's not tired to a single interface.

As soon as eth0 comes back up, the data is sent via eth0.

This causes the connection to effectively fail, where I need to use ServerAliveInterval/ServerAliveCountMax to notice and close the connection.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .