Is it safe to use DHCP Discovery to get DNS servers in my program?

I'm trying several ways to retrieve available DNS servers, for example, using a custom configuration file, using /etc/resolv.conf, using command line systemd-resolve --status.

Also I implemented a dhcp client which sends DHCP Discovery broadcast messages on all nics and collect DNS servers contained in the DHCP Offer messages, which currently works very well in my test environments.

My questions are:

  1. Is it safe to send DHCP Discovery after my host had already retrieved its IP using DHCP?
  2. Is there a better way that only retrieves domain name servers (or other DHCP parameters/options) without dhcp server allocating addresses?
  3. How often should I send the DHCP Discovery to refresh DNS? Maybe every 10 minutes?

Also I wonder:

  1. Are there other platform independent ways of getting DNS servers?

[edit 1]
Reply to "why not using getaddrinfo":
I'm trying to minimize the dependency of the platform/os. Since dns protocol uses udp, I'm able to implemented my dns client (which I've already done). So in this case I have to discover the list of available dns servers. I also run health checks for these servers to tell which are functional, so my "get-dns-servers-list" function may return as much servers as possible.

[edit 2]
Thanks a lot for your answers and comments.
Here is another reason I'm not using getaddrinfo:
getaddrinfo will block the thread and it's bad for non-blocking event loops, implementing a dns client is what network libraries usually do.
Also it's important to run every network events on the net lib's event loops to reduce context switching (usually one thread for one logical or physical core), so I'm afraid most apis outside network library are not best solutions.
Dns queries are invoked pretty often (the program may work as something like a DNS proxy). However, functions to get the list of dns servers is seldomly invoked, which may run on a "control" thread without any performance degradation.
Also I understand that DHCP may not work in some networks, so I may have to consider other protocols in the future, such as the IPv6RA which is pointed in Mahowald's answer.
Considering comments/answers mention multiple times of getaddrinfo, I'll add a toggle option to my program to fallback to using getaddrinfo on control thread if all strategies fail.


Solution 1:

Theoretically, your DHCP method should be fine, provided that (a) all of the DHCP servers and clients on the LAN are well-behaved, and (b) all of the DNS servers you want to know about are reported by the DHCP servers. On some LANs these are reasonable assumptions, on others, not. Poor quality DHCP clients (many of which are produced by at least one extremely pervasive vendor...) could damage your results. And if I needed to redetect DNS on a LAN every ten minutes, I would wonder hard about DHCP having the data.

A straightforward way to do it with high reliability, may well be to just write a simple script which runs through every IP in the LAN subnet, and tries to run 'host' or 'nslookup' using that IP.

It only has to try once per IP, unless you want to hit positive on badly functional DNS servers, which I don't advise at all. This is because the DNS protocol has a very short TTL, so to include slow-DNS detection you would have to make your script very complex with waits and retries; and this is also to be avoided because we don't want to spook any security watchdogs which may be lying around. I don't think that one (1) maximum-simplicity try per IP will spook anything, and it will give you a clear result you can use. Depending on scripting language, you could even run the lookups in parallel, five or ten at a time, to speed up the whole.

If you want to include slow-DNS detection, do it some other way, perhaps with prior knowledge of what the DNS should be, or perhaps with a script run at boot (or daemon start) on the servers to build a list somewhere for you.

And in fact, that is the other way I would be considering. If you have access to all of the servers which could run DNS, set up a script running on all of them, which writes to a text file on a central server, building a list of current DNS.

Solution 2:

Use a getaddrinfo() based library to resolve names. It works on a large number of platforms: Linux, Windows, UNIX, BSD, VMS, QNX, z/OS... Contrast to your scheme, systemd is Linux only, and not all of Linux at that.

In addition, most implementations are flexible. localhost can be hardcoded in /etc/hosts files. The system library can be upgraded independent of your application, say to add features like DNS over HTTPS.

Do not assume the system is using DHCP. RDNSS options on IPv6 RAs enable some networks to function without DHCP entirely. Or DNS may be configured statically. Outside of my network scripts, I would consider something that sends DHCP broadcasts a nuisance and will look to disable it.

Maybe you would have a use case for network diagnostic software, whose purpose is to dig into name resolution failures. Or have a fundamental disagreement with how DNS functions, such as some DNS over HTTPS implementations that went their own way. However, most software should just use the system resolver.