Hacker News new | ask | show | jobs
by geofft 3429 days ago
> They have even replaced DNS with a dbus-based protocol, which they "strongly recommend" applications use instead of DNS.

This seems inaccurate. The phrase "strongly recommend" appears once in the manpage, where it is strongly recommended that you use either the standard libc resolver API, with libnss_resolve, or the D-Bus API.

Applications should be using the libc resolver API instead of implementing DNS themselves. There are some applications like Chrome that implement DNS themselves because they care very much about DNS; those applications presumably know how to do all the things systemd-resolved does. Everyone else should get name resolution functionality from libc. That's what you've been supposed to do for decades, and it's a standard UNIX interface. That standard interface supports things like LLMNR that you don't get if you implement DNS yourself.

Unfortunately, the standard UNIX interface is synchronous, which is why libraries like ares or adns exist. If you want to use such a library, you can point it at 127.0.0.53, but you still have the limitations of what can be expressed in DNS. (And you're still using a nonstandard API to speak to libares or libadns.) No API exists that is standard, async, and does everything that libc getaddrinfo() is capable of doing. So systemd built one.

That's pretty standard behavior for systemd: implement compatibility interfaces where they exist, recommend them if they're good (systemd explicitly recommends /etc/fstab over writing native mount units, because /etc/fstab is a perfectly good format), implement them anyway if they're not, and write a better API, based on D-Bus, when needed. The latter bit not going through a multi-implementer standards committee isn't great, but it's nowhere near as bad as presented.

Anyway, this is completely irrelevant to the rest of the analysis, which seems absolutely correct, and I'm not sure why the author included this parting shot.

6 comments

Reading the man page it is actually recommending systemd-resolved over other options.

It says:

- option 1 (recommended): use systemd-resolved API.

- option 2: use glibc API with a glibc NSS module to resolve host names via systemd-resolved.

- option 3 (not recommended): local DNS stub listener on loopback to connect direct request to systemd-resolved.

Author included this part to illustrate how the real issue is that systemd is an unprecedented lock-in. Honestly an init process implementing a DNS resolver? Where is my kitchen sink ?

> Honestly an init process implementing a DNS resolver?

Systemd is a project that manages a large number of low-level services and programs that work together to try to help create a cohesive operating system.

Systemd is also the name of a init program.

These have the same name, but are not the same thing.

Systemd init process does not provide any DNS resolver features. Systemd-resolved, however, does.

Systemd is an init system, don't take my word for it[1], I seriously doubt there is any need to add a DNS resolver to an init system, especially one that reintroduced vulnerabilities.

This "project" you are talking about is this very init system + feature creep + mission creep + software bloat + interlocked dependencies to force adoption + time.

[1]: http://0pointer.de/blog/projects/systemd.html

Your reference link is nearly 7 years old. From the current project homepage [0]:

"systemd is a suite of basic building blocks for a Linux system. It provides a system and service manager that runs as PID 1 and starts the rest of the system. systemd provides aggressive parallelization capabilities, uses socket and D-Bus activation for starting services, offers on-demand starting of daemons, keeps track of processes using Linux control groups, maintains mount and automount points, and implements an elaborate transactional dependency-based service control logic. systemd supports SysV and LSB init scripts and works as a replacement for sysvinit. Other parts include a logging daemon, utilities to control basic system configuration like the hostname, date, locale, maintain a list of logged-in users and running containers and virtual machines, system accounts, runtime directories and settings, and daemons to manage simple network configuration, network time synchronization, log forwarding, and name resolution."

[0] https://freedesktop.org/wiki/Software/systemd/

To be fair to systemd, systemd-resolved is not an init process. It is its own service that just happens to integrate with systemd and is part of the wider systemd project (with journald, timesyncd, etc.)
to be fair to systemd, it is an init system with a severe case of feature creep to the point that it now includes a DNS resolver that came with vulnerabilities long fixed in the existing ones.
systemd-resolved is a separate package. It is not the init system and not a requirement of the init system.
Official systemd homepage[1] begs to differ, it says systemd is an init system including many features among which is name resolution:

>systemd (...) provides a system and service manager that runs as PID 1 and starts the rest of the system. (...) Other parts include a logging daemon, (...), log forwarding, and name resolution.

[1]: https://freedesktop.org/wiki/Software/systemd/

-edit- Not sure where it is a separate package, just checked debian and arch, the systemd package contains systemd-resolved. https://packages.debian.org/jessie/amd64/systemd/filelist https://www.archlinux.org/packages/core/x86_64/systemd/

You cut out some important parts of what you are quoting from. Although I can understand the confusion as the naming is less that stellar in this case. Let me quote part of this[1] in full and give a quick explanation of what's actually meant by it.

> systemd is a suite of basic building blocks for a Linux system. It provides a system and service manager that runs as PID 1 and starts the rest of the system.

What is being said there is that "systemd" is the name of a suite of tools (not all of which require or depend on each other, a number of them are entirely stand alone which have been adopted by the project) for Linux. Said suite provides a system and service manager that runs as PID 1, which also happens to be called "systemd". The "systemd-resolved" package is a completely separate service to the "systemd" init service, but both belong to the "systemd" project.

This is, for instance, similar to projects like KDE's Plasma which is the umbrella project for a number of related projects but also happens to be the name of the specific desktop shell.

Edit: If you really want systemd without resolved you simply pass in the --disable-resolved flag and it will build without it. It turns out that it's useful to have most of the default things systemd provides so Debian and Arch provide pretty standard builds which include resolved though.

Edit 2: If you really want to get dirty and you have the know how you can even look at the source[2]. Resolved is in its own directory and a (really) quick glance seems to indicate that it's largely independent apart from being in the systemd src/ directory.

[1] https://freedesktop.org/wiki/Software/systemd/

[2] https://github.com/systemd/systemd/tree/master/src/resolve

No, the homepage says systemd is a "suite of software" which "provides a system and service manager that runs as PID 1". The "system and service manager that runs as PID 1" is the init system. The systemd suite provides this init system.
They added the strongly from another paragraph, that's true. But the man page does recommend the dbus API over libc:

> The native, fully-featured API systemd-resolved exposes on the bus. See the API Documentation[1] for details. Usage of this API is generally recommended to clients as it is asynchronous and fully featured

> No API exists that is standard, async, and does everything that libc getaddrinfo() is capable of doing. So systemd built one.

They built an API that was async and does everything that getaddrinfo is capable of doing. They did not build an API that was standard. They did not build an API that even had the potential to become standard, because many systems do not use D-Bus, and they are not going to add it just for a slightly better DNS resolution API than what already exists.

What could they have done instead? Either or both of:

(1) Implement an extension to the DNS protocol that handles whatever extra bits they need. This is probably the best approach due to the multitude of applications that bypass libc already. Actually, I'm not convinced after reading the manpage that an extension is even necessary... what's the issue with link-local addresses? Can't they just have the DNS server on localhost synthesize records when needed? In fact, based on the rest of the manpage, aren't they already doing that? And what's the issue with Unicode? Can't they translate between DNS punycode and whatever encoding LLMNR uses?

But if an extension to DNS really is needed, it has the potential to be proposed as a standard and eventually become ubiquitous, whereas an ad-hoc replacement interface does not.

(2) (Worse idea, probably:) Propose a libc API that would be an async version of getaddrinfo with whatever enhancements are desired. Implement a portable polyfill library that either calls getaddrinfo on a thread or (if the API has extended functionality in addition to being async) uses their D-Bus stuff, depending on platform.

Admittedly, both options seem more fiddly and more work than 'just' adding some D-Bus calls. But when the existing story for name resolution is largely fully cross-platform, it seems like a bad idea to abandon that just for the sake of small improvements.

(2) already exists in at least glibc: getaddrinfo_a. Using it ~5 years ago though I found plenty of bugs in it (e.g. https://sourceware.org/ml/libc-help/2012-07/msg00024.html )

However, getaddrinfo is not a great inferface: you still can't use it to e.g. look up an MX record. For that you need res_query(3), which does not have an async interface in libc. Pottering himself wrote a library to use res_query in a separate thread http://0pointer.de/lennart/projects/libasyncns/.

However, I don't like threads, and will avoid them where possible in libraries (an example reason: I like to be in a defined state after fork()). Which means I need an async dns library that implements a resumable state machine. Lately I've been using http://25thandclement.com/~william/projects/dns.c.html

Why is (2) a worse idea ? As a programmer I would vastly prefer it over dealing with DBus myself or dealing with DNS directly
Non-DNS resolution protocols like LLMNR are almost entirely irrelevant, particularly on servers. Even if you do need asynchronous LLMNR support, you do not need dbus and a particular process running as PID 1 to get it - applications can make LLMNR queries using an asynchronous library, just like many currently use an asynchronous DNS library.

The fact that systemd keeps making decisions like this that are architecturally dubious and lead to lock-in is most certainly grounds for criticism.

When people enter a hostname into my application, I'm not particularly keen on implementing name resolving myself via DNS, LDAP, hosts file and so on in the application - It's absurd to suggest applications should make such a decision.

The current NSS system works nicely though, it just needs an async API.

Nothing systemd has done is preventing anybody from using any asynchronous library they feel like.

It's providing local name resolution services. And for very good reasons.

By your logic things like NSS is useless as well because programs themselves can read ldap configuration files and /etc/resolv.conf on their own using libraries or whatever else they feel like using.

I'm not sure why the author included this parting shot

Everybody loves kicking systemd as they re-invent various wheels; see... even I can't resist!