Reuse discovery data for name resolving

This is kind of off-topic, and I think I’ve read a similar request on the forum before–just could not find it anymore.

Syncthing has a very useful mechanism to find hosts using global discovery, yielding a public IP address (possibly over a slow link), and local discovery on the (supposedly fast) local network.

Does anyone know of a way to achieve something similar for other services? For example, I want to copy files over SCP to my server. When on LAN, it should use the fast path by resolving myserver.mydomain.com to a LAN IP. Otherwise, DNS should be considered for a DDNS registered public IP.

There could be performance problems if I always use the public DNS name, because some cheap LAN routers do not short-circuit traffic for their public IP back to the LAN, or even if they do it could limit throughput by their CPU load. So, having a “switching” solution at the resolver level (kind of Dynamic DNS at local scale) would be useful.

Of course, having a way to check whether a host on the LAN is actually the same server as what can be reached behind the public IP (and NAT) is mandatory. Syncthing natively indentifies its hosts through the certificate, other services might not be so easy to verify.

I’ve tried googling for solutions, but it seems very hard to describe the desired behavior in search-engine-friendly language. So I’m asking here if anyone knows of a solution (maybe custom dnsmasq configuration on the client) for this use case.

Maybe Syncthing’s discovery data could be exported some way to be consumed by a “switching” resolver? Open for brain storming :slight_smile:

I don’t know of a general solution for that. In the few cases where I’ve wanted to do this I’ve typically used a shell script that first pings a known local address or name and if that works it uses that, otherwise attempts to rsync/scp to another name/address.

1 Like

I use the following setups:

  • IPv6: add the global IP as AAAA record and you are done.
  • IPv4: set up a dnsmasq in the local network that returns the local IP. If you are in the local network and use this dnsmasq for name resolution, you will get the local IP, otherwise it uses the A record from DNS.

Relying solely on IPv6 is the easier option, since you only have to a´make sure that you only set a AAAA record, no A for your domain name. Of course, it will only work, if the clients that should connect using this domain name have IPv6 connectivity.

1 Like

Well, that depends on having a capable router or server on the LAN to act as dnsmasq name server, and serving its address via DHCP to clients. It’s doable, but a solution locally on the client would be easier and less complicated.

Any more ideas concerning the export of Syncthing host discovery data? Maybe this could be factored out into a service separate from file-sharing. Maybe an NSS module or a dnsmasq plugin (?) to resolve addresses like mynode.syncthing. Of course port forwarding behind NAT routers would still be problematic, but having the address without using DDNS would be a big step forward.

You should decide if you want to use DNS or syncthing then. You can already query the discovery servers when you know the device ID, not sure why you want a mapping from ID to a arbitrary name.

You can:

  • Query the discovery service directly, e.g. https://discovery-v4-1.syncthing.net/v2/?id=SR7AARM-TCBUZ5O-VFAXY4D-CECGSDE-3Q6IZ4G-XG7AH75-OBIXJQV-QJ6NLQA&device=<deviceID>
  • Use stfindevice
  • Query the discovery cache of a local syncthing instance at /rest/system/discovery

Edit: The first two options will not show you local addresses. The third will give you also the results of the local discovery. Unfortunately, there is currently no way to get the IP address in use for a device as far as I know. So you have to pick the local addresses from the addresses list by yourself.

The last part of my reply was wrong. I looked at the wrong endpoint.

So, if you have a local syncthing instance running which is currently connected to the device you want to find out the address of, you can query the /rest/system/connections endpoint, which should give you the local address if local discovery was successful and otherwise the global address.

Using DNS for discovery is not really what I want. Rather I’m looking for an easy way to tell some software to connect to “that device I know”, identified by a name or ID or anything constant.

Most software uses the OS’s name resolution facility, so what I’m interested in are solutions to hook syncthing’s knowledge into that process.

Querying Syncthing via the REST API is a good starting point. However, it is not practical to write a script for each software used that modifies the respective config file to include the discovered address. It needs to be triggered (à la PAM for example) when an application requests an address resolution of a name.

So if no practical solutions for this exist yet, writing an NSS module to query Syncthing would be the way to go. It could have a configuration file to map readable names (e.g. the same as a DDNS host name) to Device IDs, making a fallback to DNS possible.

The biggest problem with that is that Syncthing is a user process and NSS a system-wide service. The discovery results are always the same, but at least one Syncthing instance would need to be available to query. That’s kind of why I thought about separating the discovery system from the file sync.

Disregarding the connection to Syncthing altogether, for my use case it would suffice to have a fallback from myhost.local (mDNS) to myhost.dyndns.org (DDNS) if the former cannot determine an address.