TechnitiumSoftware / DnsServer

Technitium DNS Server
https://technitium.com/dns/
GNU General Public License v3.0
4.15k stars 409 forks source link

Forward-First Style Option for Custom Forwarder #973

Open Natrinicle opened 1 month ago

Natrinicle commented 1 month ago

I've been using Unbound for years and one of the most useful features is forward-first where it attempts to use the forward-addr DNS servers to resolve the domain and then falls back to recursively resolving the domain.

https://nlnetlabs.nl/documentation/unbound/unbound.conf/#forward-first

This is particularly useful for VPN connections where the private DNS server may not always be available but the VPN endpoint shares the same primary domain and the private DNS server has more records than the public one. I may not need to be on the VPN for some of the records which are both public and private so I won't necessarily start it up but once I am connected I still want access to the private records. A highly simplified example

Public Records
homeassistant.example.com
vpn.example.com

Private Records
fileserver.example.com
homeassistant.example.com

Alternatively, would it be possible to add a priority field to the custom forwarder such that I could specify the private DNS server (e.g. 192.168.0.1) as a higher priority and something upstream (e.g. 1.1.1.1) as a lower priority? If the higher priority server doesn't reply then a lower priority one could be attempted? Also perhaps an ignore bad responses like NXDOMAIN option so that things like vpn.example.com in my example could fail with the private DNS server quietly and fall back to the public DNS server but the public DNS server could have that not checked so a double (private/public) failure would actually return a failure?

ShreyasZare commented 1 month ago

Thanks for the post. Forward-first looks interesting feature but will need to think on this for a while before saying anything.

Right now, the conditional forwarder zone support this-server option for FWD record which will cause the specific domain/subdomain to resolve directly instead of using the conditional forwarder. So, in your case, you can use this for the "vpn.example.com" case where you need it to be always resolved publicly.

For the other part where you need to prefer your VPN private IP over public IP for a self hosted service, you can use the Failover APP record where in you configure your private IP as the primary and the public IP as the secondary and put in a URL in there which will be used to test connection. This APP record would automatically switch to public IP when your VPN is not connected and when it connects, the app would switch back to returning private IP. You can configure a domain name for the APP record and the use CNAME for the other domain names that need to use the same addresses.

Let me know if any of these options work for your scenario.

Natrinicle commented 1 month ago

Does this-server use the encrypted forwarders as defined in Settings->Proxy & Forwarders or does it use the one supplied via resolv.conf? I'd prefer to fall back to an encrypted upstream but am not 100% sure what method is utilized.

I considered using the Failover APP record but there are ~50 servers in my home network that would need this and several hundred in my work networks. Setting up a record for each and maintaining them would be quite a bit of work. I can't think of a good way to do this with a wildcard and in order to do it programmatically I'd have to get access to and massage the data from multiple sources.

ShreyasZare commented 1 month ago

Does this-server use the encrypted forwarders as defined in Settings->Proxy & Forwarders or does it use the one supplied via resolv.conf? I'd prefer to fall back to an encrypted upstream but am not 100% sure what method is utilized.

The DNS server does not use any system config file for its resolution process. The "this-server" feature will just route the request internally to the DNS server such that it resolves normally. So, if you have configured a forwarder in Settings, the domain will get resolved using it. If you do not have any forwarders configured then the domain name will be recursively resolved. So, yes, "this-server" will resolve via the encrypted forwarder that you have configured.

I considered using the Failover APP record but there are ~50 servers in my home network that would need this and several hundred in my work networks. Setting up a record for each and maintaining them would be quite a bit of work. I can't think of a good way to do this with a wildcard and in order to do it programmatically I'd have to get access to and massage the data from multiple sources.

Thanks for the details. In that case, it would be tough to maintain.

I think, adding a Priority option in the FWD record should work for such scenario so, that you can have 2 or more FWD records added in the forwarder zone with different Priority values. The record with highest priority will be used and if it fails to resolve the domain then the next one with lower priority would be tried. You can then have a FWD with "this-server" as low priority so that if no forwarder works then the domain gets resolved normally.

This would be kind of similar to the Preference field in MX records. Do you think this would work for you?

Natrinicle commented 1 month ago

Yeah, that was one of my original ideas for how to do this and I think it would work wonderfully!

ShreyasZare commented 1 month ago

Yeah, that was one of my original ideas for how to do this and I think it would work wonderfully!

Thanks for confirming. Will try to get this mostly in upcoming update.

ShreyasZare commented 1 month ago

There is one issue that I realized. The default config for forwarding is to use 3 retries and 2 sec timeout. So, if the priority 1 forwarder is not responding for some reason, the next priority forwarder will only be tried after 6 seconds. Till that time, users would have had a timeout error already. Is this something that would cause issues in your scenario?

Natrinicle commented 1 month ago

Yeah, this is the unfortunate downside, most software has to retry and you notice an initial delay until the record is cached. Thankfully with caching it's almost unnoticeable after the initial delay.

Perhaps if there are two forwarders with priorities set you could make the request to both simultaneously so that the failover is slightly faster?

Other than that it's still preferable to configuring a bunch of servers with failover records so I'd still really appreciate the feature being available!

ShreyasZare commented 1 month ago

Perhaps if there are two forwarders with priorities set you could make the request to both simultaneously so that the failover is slightly faster?

Yes, there will be concurrency support which will query all servers concurrently and only pickup response based on priority. This will minimize delays except in cases when there is timeout from all upstreams for the same priority.