mobile-shell / mosh

Mobile Shell
https://mosh.org
GNU General Public License v3.0
12.39k stars 726 forks source link

reconnect if server ip changed #212

Open adzeitor opened 12 years ago

adzeitor commented 12 years ago

If the server changed ip address may mosh try to reconnect to the new address.

viric commented 12 years ago

If the server address was given by name, it could attempt to re-resolve it. I'm interested in this feature too, as most disconnections to my server-behind-dynamic-ip happen for this reason.

vadipp commented 12 years ago

This would definitely be useful for my dynamic IP server with dynamic DNS set up.

cetex commented 11 years ago

I have a domain (say example.com) When resolving from the internet i get my routers public IP which does NAT to my server. At home i run a internal dns-zone to resolve example.com to my internal ip-address instead.

Result: I can always do "mosh example.com" to connect to my server. Problem: Since mosh doesn't seem to try to rediscover the server ip-address it doesnt reconnect if i go from home-network to 3g/4g or my office net, even though i think it should work.

Logic should be something like: After x seconds of connection loss, if server is specified by a hostname, do a new dns-query for the hostname and if the ip-address has changed try the new ip instead

This would also solve the ipv4/ipv6 roaming issue. As long as you use a hostname mosh should try ipv6 record first, and if that fails within X seconds, IPV4 records. If connection is lost, re-resolve the hostname and restart the procedure. IPV6 first, then IPV4.

Roaming between ipv4 and ipv6 probably isn't needed that much, at least not yet for a couple of years. There aren't that many ipv6-only sites available, so ipv4 will almost certainly always work on the server-end. But it's a nice feature none the less. :+1:

icorbett commented 10 years ago

This would be awesome as it should make mosh much more capable of switching from vpn to lan connections, and the inverse.

DaveQB commented 9 years ago

I want to vote this up. I am constantly doing the CTRL+SHIFT+6 disconnect to reconnect when I change from home network to mobile or office. Defeating the purpose of mosh in some ways.

pcchou commented 9 years ago

:+1:

mlambie commented 8 years ago

I'm very keen for this feature too. Is it on the roadmap, or even possible?

fungs commented 8 years ago

This is the reason why I have to restart mosh every 24 hours, so it would boost the usability for me.

NavinF commented 8 years ago

Has this been implemented?

From the readme:

Mosh allows the client and server to "roam" and change IP addresses, while keeping the connection alive. Unlike SSH, Mosh can be used while switching between Wi-Fi networks or from Wi-Fi to cellular data to wired Ethernet.

If the client changes IP addresses, the server will begin sending to the client on the new IP address within a few seconds.

Nippey commented 8 years ago

Plus one.

I have neither control over the internet connection nor over the respective hardware: The reconnect is unpredictable somewhere during the day.

If Mosh would try to resolve my domain name, which is updated some seconds after the reconnect, I could continue to work.

osti commented 7 years ago

I would also really appreciate this functionality. Is there any update?

fungs commented 7 years ago

For me, there are two major show stoppers in mosh and this is one of them, if you use dynamic dns on the server side (the other being firewalls blocking mosh ports).

mlambie commented 7 years ago

My workaround was to modify my internal DNS to always return the external IP for servers I connect to. Others could achieve the same thing with a static entry in their /etc/hosts file.

Importantly, this doesn't solve the problem of the server changing address dynamically, but it does solve the problem of a server resolving to a different (but static) IP within a set. In my case it was the IP allocated by my ISP, and a 10.0.0.0/8 address that DNS resolved for me when I was on the local network.

tangledhelix commented 7 years ago

I'll offer another use case for this which doesn't have to do with remote networks even. I do much of my development in a local VM on my laptop, which I connect to using a dynamic DNS name (like foo.local, using avahi-daemon and mdns). VMware seems to like changing its IP frequently, so even though I can mosh into the VM and not have it drop my session just because I sleep the laptop, it will stop working when the VM decides to change the IP. I'm not sure of a way to make VMware stop doing this.

eskhool commented 6 years ago

It looks like this bug will also go the way of the ssh-agent forwarding i.e. even if someone were to fork and implement it will not see the light of day from the core dev since none of them have even commented on this inspite of so many +1s

fungs commented 6 years ago

My summary: SSH survives only small interruptions with constant server and client IP. MOSH survives longer connection breaks and only when the client IP changes. None of them will survive an interruption due to a server IP change. Sad but true, MOSH does not live up to its promise to be an robust mobile shell not implementing this simple feature (more a bug than a feature in my opinion). In the future, even more devices which might act as terminal servers will have a dynamic IP. I probably would use MOSH every day if I would work around this bug, but I simply don't. Sorry, there is so much constructive feedback but no appreciation by the devs.

lilydjwg commented 6 years ago

Hi there, today I discover that a VPN tool, WireGuard, supports both side roaming. So you can mosh through that :-)

tlhonmey commented 5 years ago

If the documentation is accurate, if you can manage to extract the MOSH_KEY environment variable you'd then be able to reconnect to the session by calling mosh-client yourself. I'll see if I can figure out how to do this once my server comes back up.

eminence commented 5 years ago

This won't work, as the mosh crypto layer won't allow a second client to connect to an already running server. There's no way to extract the current nonce from the first client and no way to give it to the second client. #394 has some more details on this.

tlhonmey commented 5 years ago

Yeah, I noticed that. I'll have to look to see if there's a convenient place to allow punching in a different IP address since it does no name resolution itself (which is why this isn't a trivial feature I'm sure.)

If the trouble is getting the correct key to use, it could also dump the latest key to stdout on an unclean shutdown. (I'm assuming it rotates keys periodically like SSH does, but I haven't looked yet.)

tlhonmey commented 5 years ago

In src/network/network.cc you'll find a line (varies significantly with which revision you're looking at, but it's tagged with the comment, "only client can roam") where it explicitly checks if it's the server before considering whether or not to update the remote IP address.

Allowing the client to update the remote IP address as well doesn't seem to break anything, but it also doesn't seem to help (I suspect because the client isn't actually listening for incoming connections, but I haven't gotten that far yet.)

I'm still puzzling out how to plumb an ip change through from an escape character to the network layer, but I think it's possible.

Somebody who's a better C++ coder than I am might see how difficult it would be to crib the network communication methods out of the Syncthing project. STUN and relay support would make this work in more than just the best case of having control over the firewalls and NATs that are in the way.

ChaiTRex commented 5 years ago

@tlhonmey The server gets the client's new address from new packets sent to it by the client. It's not going to work to have the client get the server's address that way, since the server isn't going to be sending data forever to a client that doesn't seem to be there anymore, so there's probably not any packets from the server to receive.

For example, the client loses network access, then the server switches addresses, then five hours later, the client gets network access again. You wouldn't expect the server to be broadcasting for five hours to the last-known address of the client because the idea of Mosh is that the client can change addresses at any moment, so why keep the server sending to an address that may be dead or may belong to someone else now?

Even if Mosh was going to be wasteful and rude to some stranger who got the client's old address, it won't work if both the server and client have switched addresses, since the server isn't sending anything to the new client address and the client isn't sending anything to the new server address, so a solution that addresses all these basic cases will have to be something else.

cetex commented 5 years ago

To support the server changing IP the client would have to resolve DNS again and then just try to reconnect on both ipv4 and/or ipv6 to see if the same server is still there.

ChaiTRex commented 5 years ago

@cetex One important thing is that there should be two classes (as in classification, not object-oriented programming) of addresses it should try to reconnect to:

The only ways to update these classes are, respectively:

Neither of the two classes can erase or modify the addresses in the other class.


Note that the second class (addresses that DNS gives us) should be stored even from the time we initially connect to the Mosh server. That way, if we lose the connection and DNS is flaky later on, perhaps a different IP address we initially got from DNS will work.


When trying the two classes of addresses, we should take a bit of care to ensure that, if the address in the first class is also in the addresses in the second class, we don't try to connect to it double the number of times as other addresses in the second class.

tlhonmey commented 5 years ago

@ChaiTRex Yeah, it didn't work. Adding a server -> client heartbeat is more than I know how to do currently, but might make it work as long as only one address changes at a time (which is probably the most common use case.)

If the server address is going to change, then the user of the client will need some way to know what the current address is in order to even make the connection. Normally this is probably DNS.

Unfortunately the mosh client doesn't actually do name resolution, it relies on its wrapper to look up the IP for it. So it's not as simple as just having it re-resolve the name and reconnect. The other solution I will try to look into when I have more time is to add an escape key option that will tell the client to grab a new server address from somewhere. But this project is too complex for me to load it into my head without having bigger chunks of time to allot to it than I currently can spare, so that will probably take me a while.

unode commented 5 years ago

For those of you landing on this question, if your mosh server changed address but the new address is reachable you can circumvent the issue with firewall/routing changes.

In my case I had a connection to an external IP address. When inside the network the IP was not reachable. Since DNS to the same hostname resolved to an internal address and I could mosh to this IP without problems, using:

iptables -t nat -A OUTPUT -d IP.used.by.mosh -j DNAT --to-destination new.IP.to.use

allowed me to recover my mosh sessions.

The same principle can be used for most cases where IP changes.

fungs commented 5 years ago

@unode, that's a nice hack. It should also be possible to do this in userspace without needing root using netcat/socat or something like NUSE and always connecting to a static local ip which is redirected by one of these tools. A clever wrapper would then achieve what we want. Of course, it would be much nicer to have proper hostname resolution in mosh :)

cespedes commented 5 years ago

Is there a roadmap to try to add this feature, or at least are the developers open to patches to fix this issue?

fayeshine commented 4 years ago

@keithw @cgull please help, we need this feature

mlambie commented 4 years ago

For me this is an issue connecting to mosh-servers that are available on the LAN and via WAN with port forwarding. I use the following function in zsh to bounce through a bastion server, regardless of my location (internal to the LAN or external). Mosh to the bastion which will keep the connection open, then regular SSH from the bastion to the target host.


mosh () {
        case $@ in
                (lifeline)  ;&
                (lifeline.domain.com) command mosh dialtone.domain.com -- bash -c 'echo "Bouncing via dialtone..." && echo && ssh lifeline.domain.com' ;;
                (*) command mosh "$@" ;;
        esac
}
PenelopeFudd commented 2 years ago

I'd solve this a different way:

The thing preventing this from working 100% of the time is that the client may be behind a NAT firewall: if the server changes ip addresses, the firewall isn't going to forward packets from the new address.

There are a couple of workarounds for this developed for VOIP applications: UDP hole punching and the STUN protocol.

Actually, because this protocol uses UDP, there's another way to make it work:

Once the holes are set up, they may stay up without having to keep sending more hole-punching packets, depending on the NAT's settings

Essentially, this is UDP hole-punching but without the third-party server.

albertz commented 1 year ago

@keithw @cgull @bbarenblat @achernya I'm familiar with C++ and I assume I can implement this. But there have been no response by any of the maintainers (you?) whether this is a wanted feature, and which of the suggestions should be implemented.

I see two suggestions here:

I think both suggestion could be implemented independently. For now, I would just implement the first proposed suggestion, as it should be simple, and already solve the problem for most users.

So, should I submit a PR which implements that?

I also saw that there is already the very related PR https://github.com/mobile-shell/mosh/pull/600.

There was one concern about getting a different host behind a round-robin DNS load balancer. But I see some solution to that problem: Check temporarily for a new IP, and only keep it if we can make the connection, otherwise don't keep it.

There was another concern about clogging a slow connection with frequent re-resolving the domain. I don't think this is a problem, if you only do this every N seconds or so.

bbarenblat commented 1 year ago

This is a feature I want, and I know this is a feature @achernya wants too. We believe re-resolving DNS is the way to go, at least for now. I will happily review a PR that implements this, either a modified https://github.com/mobile-shell/mosh/pull/600 (cc: @nogy) or a new one.

Ideally, DNS re-resolution would happen automatically, whenever the connection to the server is down for a few seconds. It’s important that it not block the UI. I don’t remember what the state of asynchronous DNS resolution on POSIX systems is these days, so this might involve spinning up a new thread.

Additionally, any implementation should be off by default and behind a flag, at least for now. Once we’ve gathered enough user experience reports to verify that it works in the real world, we can turn it on for everyone.

M0rtenB commented 2 months ago

I too am looking for this!