jamulus icon indicating copy to clipboard operation
jamulus copied to clipboard

Improved NAT support part N+1

Open pljones opened this issue 3 years ago • 9 comments

Background

This is more a statement of a problem rather than a specified feature...

A Jamulus service provider is running a number of physically separate servers on a LAN behind a NAT connection to the internet.

ServerA runs Jamulus server on port Port1 and registers with an external directory server.

  • This means the external directory server will receive a UDP packet populated with the external IP address ExternalIP and the NAT port forwarding port assigned to ServerA:Port1 by the provider's router PortT.
  • When registering, the server will have supplied its internal IP address, ServerA.
  • The external directory server will ping back to ExternalIP:PortT, which the provider's router will recognise as ServerA:Port1
  • This allows other external connections from the internet to ExternalIP:portT to route to the correct Jamulus server
  • Internally, the Jamulus server has no knowledge of "portT" at the router and is listening on ServerA:Port1
  • When an internal client consults the external directory, it receives ServerA:PortT back (rather than ExternalIP:PortT)
  • If Port1 and PortT are the same, this is not a problem - internal clients can connect using the external directory

If ServerB (on the same LAN as ServerA) runs a Jamulus server also on Port1 and registers with an external directory server,

  • The external directory server will receive a UDP packet populated with the external IP address ExternalIP and the NAT port forwarding port assigned to ServerB:Port1 by the provider's router PortS.
  • PortS and PortT cannot be the same - the router wouldn't be able to route to the correct internal IP:port.
  • When registering, the server will have supplied its internal IP address, ServerB.
  • When an internal client consults the external directory, it receives ServerB:PortS back (rather than ExternalIP:PortS)
  • This is now a problem.
    • Both ServerA and ServerB are listening on Port1, which is okay, as they're different IPs.
    • However, Port1 cannot be both PortT and PortS, as these must be different values as they're on ExternalIP

ServerE (on the same LAN as ServerA and ServerB) is running a Jamulus directory server (helpfully not on Port1 but on PortD).

ServerC (still same LAN) registers a Jamulus server on Port1 with ServerE.

ServerD (still same LAN) registers a Jamulus server on Port1 with ServerE.

I don't quite understand how ServerE is exposed to the internet (how PortD gets forwarded to ServerE) - presumably some how it's generating source traffic on PortD and hence incoming requests get to ServerE? Anyway, seems to work mostly...

ServerC and ServerD now are virtually invisible, though -- they should be listed on ServerE but incoming requests to them have no external details...

The new --serverpublicip has allowed ServerC and ServerD to specify their external IP ExternalIP. However, they would both appear on Port1 - and as the list is maintained by external IP:port, that means only one is in the list.


The feature request

As a minimum, the Jamulus directory needs to support a registering server supplying a public port, along with its public IP. However, in a similar way to the internal IP, the internal port should be returned to internal lookups.

pljones avatar Apr 30 '21 08:04 pljones

As a minimum, the Jamulus directory needs to support a registering server supplying a public port, along with its public IP. However, in a similar way to the internal IP, the internal port should be returned to internal lookups.

It may be possible to simply provide a way to override the port here: https://github.com/jamulussoftware/jamulus/blob/6560b68636cc7dfd01f489a5374b25a27e3033b4/src/serverlist.cpp#L57

(similar to --serverpublicip)

This would end up in the "internal port" field of the registration protocol message. This would be OK, IMO, but we should think about renaming both "internal port" and "internal address" to "alternative port" and "alternative address".

I haven't tried it, but I don't see anything preventing this from working right now.

@softins indicated that he planned to look into that.

hoffie avatar Apr 30 '21 10:04 hoffie

@softins indicated that he planned to look into that.

Yes, I do. Had planned to do so today, but will likely be delayed till tomorrow.

softins avatar Apr 30 '21 11:04 softins

There are a number of elements we need to track:

  • Server internal IP
  • Server internal Port
  • Server public IP
  • Server public Port

When the directory is outside the LAN, it needs to return the "internal" details to any host looking up from the same public IP but return the "public" details to any other host.

When the directory is inside the LAN, it needs to return the "internal" details to any host looking up from the same internal IP but the "public" details to any other host.

When a server registers, prior to --serverpublicip, the only way the directory used to determine public details was the UDP message source IP and port.

Suggested change: if the UDP source IP is on the local LAN, use the UDP source details for the internal details by default and require provision of the public details. (Or, at least, if they're not specified, say in the log the server won't be visible -- unfortunately it would be a potentially breaking change to send back a new "You really didn't want to do that, did you" non-error response.)

So yes, "alternative" sounds like a good approach. The directory knows what it can determine. It knows, therefore, what it needs to find from the additional details in the registration message.

pljones avatar Apr 30 '21 18:04 pljones

I'm still wondering about "punching" the hole in the modem for incoming traffic though. One idea I had (and squashed) was to "self ping" using the public details, from the bound socket. This would tell the modem "Hello, there's UDP traffic between <local IP>:<local Port> and <public IP>:<public Port>" and it might just be bright enough to go "Oh! I have a rule for <public Port> that says it's allowed but should go to <local Port> -- I'll assume that's you, then, right?"

This ping could happen at the same time as the regular server registration message -- or more frequently if that proved not enough in practice. If it worked at all. (Only if the directory was internal, of course.)

pljones avatar Apr 30 '21 18:04 pljones

As we apply Jamulus to more and more combinations of servers and clients distributed across private networks, firewalls, and public networks, we are rediscovering use cases solved by DNS. Is it possible that our efforts are better used to find a migration path to leverage the DNS infrastructure. If we can create a dynDNS function as part of the directory server, all these public/private address combinations can be solved. It seems to me the big hurdle is helping the Jamulus community to avoid buying domain names so that their servers can have a FQDN.

Yes, I don't know the complexities of adding FQDN to our servers. I just find it frustrating to see all the brian power inventing a solution for problems that should be using DNS. If we don't use DNS, then every owner of a server with these configurations must know how to manage these addressing challenges with whatever mechanism is invented. (I am assuming whatever solution is created, human intervention will be required to accommodate/coordinate non-Jamulus uses of the firewall.)

gene96817 avatar Apr 30 '21 20:04 gene96817

Regarding a Jamulus dynDNS service. What if there is a dynDNS service giving all Jamulus servers a FQDN of the form serverX.jamulus.io? This would bind the public IP address to serverX. Now anyone with clients inside their local firewall just has to give their router a host entry serverX.jamuilus.io=localaddr. Now all the local clients can function with no new address tricks. The local router/firewall would apply the localaddr.

gene96817 avatar Apr 30 '21 20:04 gene96817

DNS doesn't come into issues within an LAN. It doesn't solve issues where internal and external IP addresses differ or internal and external port numbers differ.

pljones avatar Apr 30 '21 21:04 pljones

DNS doesn't come into issues within an LAN.

I have some FQDN in my router host table. It provides the local IP to the local devices. In that way, no local device needs to know the local address assignment. Only the router (local) host table needs to know. The router provides DNS forwarding for all other FQDN.

gene96817 avatar Apr 30 '21 21:04 gene96817

If your router supports things like that and you're happy to set the configuration, that's good. Most cheap domestic ISP routers don't. Most domestic Jamulus users couldn't set them up if they did.

pljones avatar May 01 '21 08:05 pljones

Closing, as I seem to have fixed it.

pljones avatar Oct 05 '22 09:10 pljones