mjl- / mox

modern full-featured open source secure mail server for low-maintenance self-hosted email
https://www.xmox.nl
MIT License
3.71k stars 113 forks source link

Feature request: support for sytemd-resolved. #38

Closed ArnoSen closed 1 year ago

ArnoSen commented 1 year ago

When running quickstart, I get errors like this:

WARNING: checking your public IP 46.19.33.172 in DNS block list sbl.spamhaus.org: temperror  (dnsbl: dns error: lookup 172.33.19.46.sbl.spamhaus.org. on [::1]:53: read udp [::1]:56813->[::1]:53: read: connection refused)

I checked the DNS config on my 'out-of-the-box' VPS and apparently it is configured with systemd-resolved. I wil find my way around it but it would be nice if mox would work with systemd-resolved.

mjl- commented 1 year ago

Thanks for the report. My first guess is that this isn't a mox-specific issue. Mox doesn't do anything special to configure DNS servers, or how it talks to them. Are you running this inside docker or directly on the system? And what is in /etc/resolv.conf? It looks like for systemd-resolved, the file /etc/resolv.conf should consist of a line like nameserver 127.0.0.53. But the error message indicates mox is trying to resolve through DNS server ::1 (localhost ipv6).

If you run dig 172.33.19.46.sbl.spamhaus.org, does that work, and which nameservice is used? This IP isn't in the spamhaus blocklist, which means you should get a "status: NXDOMAIN" response.

By the way, it appears that systemd-resolved does not validate dnssec signatures by default. You could enable that (once everything is working), but I personally prefer installing unbound.

ArnoSen commented 1 year ago

I have no experience with systemd-resolved at all.

/etc/resolv.conf is empty but DNS resolution works.

When I run dig I get: dig 172.33.19.46.sbl.spamhaus.org ;; communications error to ::1#53: connection refused ;; communications error to ::1#53: connection refused ;; communications error to ::1#53: connection refused ;; communications error to 127.0.0.1#53: connection refused

; <<>> DiG 9.18.15 <<>> 172.33.19.46.sbl.spamhaus.org ;; global options: +cmd ;; no servers could be reached

Reading https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html, it says:

Local applications may submit network name resolution requests via three interfaces:
- The native, fully-featured API systemd-resolved exposes on the bus, see [org.freedesktop.resolve1(5)](https://www.freedesktop.org/software/systemd/man/org.freedesktop.resolve1.html#) and [org.freedesktop.LogControl1(5)](https://www.freedesktop.org/software/systemd/man/org.freedesktop.LogControl1.html#) for details. Usage of this API is generally recommended to clients as it is asynchronous and fully featured (for example, properly returns DNSSEC validation status and interface scope for addresses as necessary for supporting link-local networking).

- The glibc [getaddrinfo(3)](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html) API as defined by [RFC3493](https://tools.ietf.org/html/rfc3493) and its related resolver functions, including [gethostbyname(3)](https://man7.org/linux/man-pages/man3/gethostbyname.3.html). This API is widely supported, including beyond the Linux platform. In its current form it does not expose DNSSEC validation status information however, and is synchronous only. This API is backed by the glibc Name Service Switch ([nss(5)](https://man7.org/linux/man-pages/man5/nss.5.html)). Usage of the glibc NSS module [nss-resolve(8)](https://www.freedesktop.org/software/systemd/man/nss-resolve.html#) is required in order to allow glibc's NSS resolver functions to resolve hostnames via systemd-resolved.

- Additionally, systemd-resolved provides a local DNS stub listener on the IP addresses 127.0.0.53 and 127.0.0.54 on the local loopback interface. Programs issuing DNS requests directly, bypassing any local API may be directed to this stub, in order to connect them to systemd-resolved. Note however that it is strongly recommended that local programs use the glibc NSS or bus APIs instead (as described above), as various network resolution concepts (such as link-local addressing, or LLMNR Unicode domains) cannot be mapped to the unicast DNS protocol.

    The DNS stub resolver on 127.0.0.53 provides the full feature set of the local resolver, which includes offering LLMNR/MulticastDNS resolution. The DNS stub resolver on 127.0.0.54 provides a more limited resolver, that operates in "proxy" mode only, i.e. it will pass most DNS messages relatively unmodified to the current upstream DNS servers and back, but not try to process the messages locally, and hence does not validate DNSSEC, or offer up LLMNR/MulticastDNS. (It will translate to DNS-over-TLS communication if needed however.)

From this I read that DBUS is the preferred way to resolve using systemd-resolved.

mjl- commented 1 year ago

If /etc/resolv.conf is empty, there's certainly something missing on the machine. It's kind of strange that a new machine wouldn't set up /etc/resolv.conf properly. It has been the place where DNS configuration is stored for decades. I searched around a bit, and for debian I saw mention of package resolvconf, which appears to keep /etc/resolv.conf correct (https://packages.debian.org/bullseye/resolvconf). Which distribution are you using? Perhaps it has a similar package.

ArnoSen commented 1 year ago

I am running Arch.

When reading https://manpages.ubuntu.com/manpages/bionic/man8/systemd-resolved.service.8.html, it says:

Four modes of handling [/etc/resolv.conf](file:///etc/resolv.conf) (see [resolv.conf](https://manpages.ubuntu.com/manpages/bionic/man5/resolv.conf.5.html)(5)) are supported:

       •   systemd-resolved maintains the [/run/systemd/resolve/stub-resolv.conf](file:///run/systemd/resolve/stub-resolv.conf) file for
           compatibility with traditional Linux programs. This file may be symlinked from
           /etc/resolv.conf. This file lists the 127.0.0.53 DNS stub (see above) as the only DNS
           server. It also contains a list of search domains that are in use by systemd-resolved.
           The list of search domains is always kept up-to-date. Note that
           [/run/systemd/resolve/stub-resolv.conf](file:///run/systemd/resolve/stub-resolv.conf) should not be used directly by applications, but
           only through a symlink from [/etc/resolv.conf](file:///etc/resolv.conf). This file may be symlinked from
           /etc/resolv.conf in order to connect all local clients that bypass local DNS APIs to
           systemd-resolved with correct search domains settings. This mode of operation is
           recommended.
(...)

I will be able to solve this, no problem. Then the question remains if mox should support making DNS calls to systemd-resolved in the preferred manner. At this moment systemd classifies mox as a "traditional Linux program" :smile:

(NB: the other options mentioned basically do the same)

ArnoSen commented 1 year ago

Also interesting to read is https://pkg.go.dev/net#hdr-Name_Resolution. The default for go is to read from /etc/resolv.conf unless you enable CGO that will call C library routines for DNS resolution with which systemd-resolved should be compatible.

mjl- commented 1 year ago

Good info.

It would be handy for users if mox could talk to the systemd-resolved. But I'm not enthousiastic about using cgo. It makes reproducible builds and cross-compilation much harder, and it makes it harder to use pre-compiled binaries: I've recently had several cases where a Go cgo binary compiled on one linux wouldn't run on another due to glibc symbol incompatibilities. The Go toolchain is built without cgo now because of this (https://github.com/golang/go/issues/57007).

If the systemd-resolved interface is easy enough to implement (one would hope so!), perhaps the Go standard library will grow support for it.

But it still seems like /etc/resolv.conf should just have a proper configuration on all systems. The "Note"-section at https://wiki.archlinux.org/title/systemd-resolved#DNS says "Failure to properly configure /etc/resolv.conf will result in broken DNS resolution". I'm wondering how commonly this happens, and if it is on purpose that this isn't set up by default on arch.

Perhaps the best that mox can do for now is to recognize if this is happening. I'm going to see if I can get mox to give a helpful hint in the error message if resolving fails with a "connection refused" when the dns server when is 127.0.0.1:53" or "[::1]:53 (https://cs.opensource.google/go/go/+/refs/tags/go1.20.5:src/net/dnsconfig.go;l=14). That should help folks solve the issue without having to start a debugging session.

mjl- commented 1 year ago

Some weeks ago, mox got support for DNSSEC-awareness when doing DNS lookups through a (local) recursive resolver (like unbound, but also systemd-resolved). I've been using unbound, but I also looked at systemd-resolved and its DNSSEC support. It turns out DNSSEC support in systemd-resolved doesn't actually work, and when asked about it is claimed experimental. I wouldn't recommend using systemd-resolved at all. Now that I've done a bit more with DNS, I also think the right API to DNS is just DNS, not some custom systemd-resolved API, so I don't plan on implementing support for systemd-resolved.