qdm12 / ddns-updater

Container to update DNS records periodically with WebUI for many DNS providers

Home Page:https://hub.docker.com/r/qmcgaw/ddns-updater/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Domain resolution is resolving to internal IP causing constant record updates

cybersteel8 opened this issue · comments

TLDR: Hostname resolution should explicitly use an external DNS provider

  1. Is this urgent: No
  2. DNS provider(s) you use: No-IP
  3. Program version: Running version latest built on 2022-11-03T09:49:13Z (commit d8de9d2)
  4. What are you using to run the container: Unraid docker app
  5. Extra information:

My server's default DNS resolver is my router, and in my router's configuration I have the domain used here overridden to return the internal IP. This applies only inside the local network, so the domain when accessed externally points to my external IP, as is governed by No-IP.
This means that DNS resolution of the domain name using the default DNS server, eg. 192.168.0.1 (the gateway) will never return the correct IP. To resolve the domain, any external DNS server should be used, like 1.1.1.1 or something else.
This is confusing ddns-updater and causing the domain to never match the external IP and it is always updating it, every cooldown.
If ddns-updater could be configured to specifically use an external DNS server, such as google or cloudflare or quad9 to resolve the domain name, this would return the correct response.

Logs:

INFO IPv4 address of <domain> is <internal IP> and your IPv4 address is <external ip>

Configuration file:

{
  "settings": [
    {
      "provider": "noip",
      "domain": "<redacted>",
      "host": "@",
      "username": "<redacted>",
      "password": "<redacted>",
      "ip_version": "ipv4",
      "provider_ip": true
    }
  ]
}

Host OS: Unraid 6.11.1

I resolved this by setting a custom dns on the container.

For example with docker run:
docker run ... --dns=1.1.1.1 ...

or with docker-compose:

version: "3.7"
services:
  ddns-updater:
  ...
    dns:
      - 1.1.1.1
  ...

That's good advice, and I gave it a shot, but sadly it doesn't seem to work (or isn't respecting that environment variable)
Is it possible via an environment variable? I may need to wrangle Unraid to apply this flag not as -e but instead as literally --dns in the docker run command. This is basically what Unraid is doing:

docker run
  -d
  [...]
  -e 'dns'='1.1.1.1'
  [...]

...which isn't what you meant, is it?

EDIT: Yeah, it appears that executing the docker run command manually in terminal using Unraid's output but changing the dns environment variable to be a direct flag seems to work.

Thanks a lot! That works perfectly for me too.
I wouldn't say this is a bug per se in my case, this is due to my network setup (something.mydomain.com resolves to an internal IP inside my network but to my public IP outside my network). I wouldn't say there's anything DDNS updater should do to cater for my stuff, but that trick with the DNS property on docker-compose is worth writing down somewhere maybe in the docs.

I've made a pr #417 addressing this issue. Feel free to comment, if I missed something.

Thanks @affeldt28 for the PR. Commit 464a557 should put a nail into it, you can now use RESOLVER_ADDRESS=1.1.1.1:53 for example to use Cloudflare only for the domain name resolution part of the ddns program and not the whole container. By default, I think it's best to keep it as the default docker DNS (otherwise i.e firewall could be blocking it). Cheers everyone

commented

@cybersteel8 @qdm12 is it better to use an Authoritative Server as resolver or the classic 1.1.1.1 is enough?

Also, what is the best value for the TTL setup with a DDNS service?

First the easy answer:

what is the best value for the TTL setup with a DDNS service?

As short as possible. When your public ip address changes, you want the DNS records to update as quickly as possible depending on your needs. Usually 5 minutes is fine, otherwise you should really get a fixed ip.

is it better to use an Authoritative Server as resolver or the classic 1.1.1.1 is enough?

DNS over port 53 udp is in plaintext and unencrypted, and there is no cryptographic verification by default, so really it doesn't matter, one could manipulate your traffic and feed you a bad ip address anyway. BUT It doesn't matter much since ddns updater is using this to check against your public ip address. In the worst case, it will just trigger the update more often.

Now in the depth of technicalities for the paranoid, we could either:

  • trust a provider such as Cloudflare which validates DNSSEC and use DNS over TLS (encrypted dns traffic) to exchange with them; or
  • check DNSSEC ourselves but then you cannot use DNS over TLS (you need to go from the root dns server down to your authoritative dns server, and most don't support dns over tls)

DNS over tls is great for privacy, whilst DNSSEC is great to make sure a record is correct without relying on i.e. Cloudflare, which might be more interesting here.
Now DNSSEC is enabled on very few domains, maybe yours, and is complicated to validate right (I am working on https://github.com/qdm12/dns/tree/dnssec/pkg/dnssec). My take on it is pick the provider you want to trust such as Cloudflare, let them validate DNSSEC when it's present (they will not given you invalid DNSSEC records), and exchange over TLS so your traffic cannot be tempered.

But DNS over TLS is not implemented in ddns updater yet (not so much of a need yet), maybe I'll get to it one day.

commented

@qdm12 Thank you very much for the details. I will follow your suggestions. However, just for curiosity, wouldn't this be a security issue if used together with PUBLICIP_FETCHERS=dns? An attacker could change the answer for both public IP and DNS answer in a very specific and targeted attack in order to change the ip of my domain?

That's a very good point I didn't realize, can you create an issue copy pasting your comment?

I'll check if they have these public ip echo endpoints with dns over tls, and, if not, at least default to http(s) and not http+dns for the public ip fetchers.

commented

Done