I have this nftables rule:
ip daddr { "0.nixos.pool.ntp.org", "1.nixos.pool.ntp.org", "2.nixos.pool.ntp.org", "3.nixos.pool.ntp.org" } udp dport ntp accept comment "Allow NTP traffic for system time"
The goal is to allow NTP traffic from a host that otherwise denies most traffic (default reject policy). The hostnames in the rule come from the system's default NTP configuration (so they're the same hostnames the NTP daemon is configured with).
It fails to load, however, because 0.nixos.pool.ntp.org
(and the others) have multiple addresses:
$ host 0.nixos.pool.ntp.org
0.nixos.pool.ntp.org has address 66.228.42.59
0.nixos.pool.ntp.org has address 216.229.4.66
0.nixos.pool.ntp.org has address 216.229.0.50
0.nixos.pool.ntp.org has address 69.10.161.7
So nftables complains and refuses to load the ruleset:
# nft -f ...-nftables-rules
...-nftables-rules:37:16-37: Error: Hostname resolves to multiple addresses
ip daddr { "0.nixos.pool.ntp.org", ... } udp dport ntp accept comment "..."
^^^^^^^^^^^^^^^^^^^^^^
These domain names are outside of my control. Thus, I can't stop them from resolving to multiple addresses. I also don't know when the address records associated with them might change.
How should I write my nftables ruleset to deal with this case?
To clarify up front: this isn't an answer to your question about nftables. It's to offer some other options.
If you fully control the machine in question (i.e. there are no untrusted users who might produce malicious NTP queries), then there's no substantive difference to security by allowing outbound NTP to any server versus allowing access to only the servers returned by the DNS query, because the NTP pool is guaranteed to change those hostnames based on the weights of the servers in the pool. So the simple solution is just to allow all outbound NTP.
If you have untrusted users and want to lock down your rules to allow only the IPs that are returned by the NTP pool DNS server for those specific names and you use dnsmasq as your resolver (or are willing to switch to it), then one option might be to use dnsmasq to populate an ipset, and then refer to that ipset in your nftables rule (assuming that nftables supports ipsets). I use this with iptables to limit certain outbound traffic (e.g. HTTPS) to only those domains I know I want to use, without needing to know the IP addresses in advance.
If you follow the latter approach, use ipset definitions something like this:
along with a dnsmasq option like this:
With the above configuration, dnsmasq will add IPv4 addresses for names it resolves to the
ntp
ipset, and IPv6 addresses to thentp-inet6
ipset. Then you can refer to those ipsets in your rules. You can also configure a timeout on the ipsets, but that's probably inadvisable in this case, because NTP will keep using pool servers for long periods of time after querying DNS, if the source is found to be stable.