#8275 Support systemd-resolved
Closed: fixed 2 years ago by cheimes. Opened 2 years ago by abbra.

Fedora 33 is planning to enable systemd-resolved by default. The change is described in detail in https://fedoraproject.org/wiki/Changes/systemd-resolved

FreeIPA needs to be ready for systemd-resolved operation by Fedora 33. FreeIPA does modification of resolv.conf when installed with DNS and it also expects to fix resolv.conf on the test systems in own integration tests. Since resolv.conf would become a symlink some of the expectations might not be true anymore.

We need to find out what actual tasks need to be done to preserve current FreeIPA behavior with regards to DNS and DNSSEC operations.


Metadata Update from @abbra:
- Issue set to the milestone: FreeIPA 4.8.7

2 years ago

It might be sufficient to drop in a config file and reload systemd-resolved

# /etc/systemd/resolved.conf.d/ipa.conf
[Resolve]
DNS=127.0.0.1
Domains=~.

It might also be advisable to configure dnssec trust anchors and add our DNSSEC KSK.

Metadata Update from @cheimes:
- Issue set to the milestone: None (was: FreeIPA 4.8.7)

2 years ago

Metadata Update from @cheimes:
- Issue priority set to: important
- Issue set to the milestone: FreeIPA 4.8.7

2 years ago

Rawhide doesn't use systemd resolved yet. We have to wait until the new feature is implemented.

Metadata Update from @cheimes:
- Issue set to the milestone: None (was: FreeIPA 4.8.7)

2 years ago

Metadata Update from @abbra:
- Custom field rhbz adjusted to https://bugzilla.redhat.com/show_bug.cgi?id=1880628

2 years ago

Fedora 33 now uses systemd resolved and we've got bug https://bugzilla.redhat.com/show_bug.cgi?id=1880628 as accepted exception to fix the behavior.

Metadata Update from @abbra:
- Issue set to the milestone: FreeIPA 4.8

2 years ago

--auto-forwarders is not compatible with systemd-resolved yet. Internally the flag uses dnspython to get a list of name servers with dns.resolver.get_default_resolver().nameservers / get_ipa_resolver() since #8383. On Fedora 33 this returns the stub resolver ['127.0.0.53']. FreeIPA either needs to parse the output of resolvectl dns (ugly) or use D-Bus to query the DNS resolver information for global scope and all link scopes.

code to detect if systemd-resolved manages /etc/resolv.conf

import os
from ipaplatform.paths import paths

def detect_resolve1_resolv_conf():
    """Detect if /etc/resolv.conf is managed by systemd-resolved

    See man(5) NetworkManager.conf
    """
    systemd_resolv_conf = {
        "/run/systemd/resolve/stub-resolv.conf",
        "/run/systemd/resolve/resolv.conf",
        "/lib/systemd/resolv.conf",
        "/usr/lib/systemd/resolv.conf",
    }
    try:
        dest = os.readlink(paths.RESOLV_CONF)
    except OSError:
        # not a link
        return False
    # convert path relative to /etc/resolv.conf to abs path
    dest = os.path.normpath(
        os.path.join(os.path.dirname(paths.RESOLV_CONF), dest)
    )
    return dest in systemd_resolv_conf

code to get upstream nameservers from systemd-resolved's D-Bus interface

import socket
import dbus

DBUS_RESOLVE1_NAME = "org.freedesktop.resolve1"
DBUS_RESOLVE1_PATH = "/org/freedesktop/resolve1"
DBUS_RESOLVE1_MANAGER_IF = 'org.freedesktop.resolve1.Manager'
DBUS_PROPERTY_IF = 'org.freedesktop.DBus.Properties'
# netlink interface index for resolve1 global settings and loopback
IFINDEX_GLOBAL = 0
IFINDEX_LOOPBACK = 1

def get_resolve1_nameservers():
    """Get list of DNS forwarders from systemd-resolved

    :return: list of tuples (ifindex, ipaddress)
    """
    bus = dbus.SystemBus()
    try:
        resolve1 = bus.get_object(DBUS_RESOLVE1_NAME, DBUS_RESOLVE1_PATH)
        prop_if = dbus.Interface(resolve1, DBUS_PROPERTY_IF)
        dns_prop = prop_if.Get(DBUS_RESOLVE1_MANAGER_IF, "DNSEx")
    finally:
        bus.close()
    results = []
    for ifindex, af, dns_arr, port, sniname in dns_prop:
        if af not in {socket.AF_INET, socket.AF_INET6}:
            # neither IPv4 nor IPv6
            continue
        if port not in {0, 53} or sniname:
            # non-default port, non-standard port, or SNI name configuration
            # for DNS over TLS, e.g. 1.2.3.4:9953#example.com
            continue
        # netlink interface index, see socket.if_nameindex()
        ifindex = int(ifindex)
        dnsip = socket.inet_ntop(af, bytes(dns_arr))
        results.append((ifindex, dnsip))
    return results

```

Using socket.if_indextoname() you can get back the interface name:

....
     results.append((ifindex, socket.if_indextoname(ifindex), dnsip))

Metadata Update from @cheimes:
- Custom field on_review adjusted to https://github.com/freeipa/freeipa/pull/5125
- Issue assigned to cheimes
- Issue priority set to: critical (was: important)

2 years ago

master:

  • 96edff0 Add helpers for resolve1 and nameservers
  • e64f27f Configure NetworkManager to use systemd-resolved
  • 528c519 Use new API for auto-forwarders
  • d12f1b4 Configure systemd-resolved to use IPA's BIND
  • 79b9982 Create systemd-resolved configuration on update

ipa-4-8:

  • 489ddc6 Add helpers for resolve1 and nameservers
  • d6827f5 Configure NetworkManager to use systemd-resolved
  • 6dc5566 Use new API for auto-forwarders
  • c67aba2 Configure systemd-resolved to use IPA's BIND
  • 3b3cb99 Create systemd-resolved configuration on update

Metadata Update from @abbra:
- Custom field changelog adjusted to FreeIPA DNS servers now detect systemd-resolved and configure it to pass through itself.

2 years ago

Upgrade does not yet work well, I filed a separate issue https://pagure.io/freeipa/issue/8518 for this problem

master:

  • 34e4777 Ensure that resolved.conf.d is accessible
  • ced1dcb Also backup DNS config drop-ins

ipa-4-8:

  • e9824b5 Ensure that resolved.conf.d is accessible
  • 2f44efc Also backup DNS config drop-ins

Metadata Update from @cheimes:
- Issue close_status updated to: fixed
- Issue status updated to: Closed (was: Open)

2 years ago

I found a potential issue with my code. If the server has multiple NICs with multiple IP addresses than the new code might add "127.0.0.1" and "::1" to /etc/resolv.conf multiple times.

The get_server_ip_address(host, True, False, []) should be equivalent to resolve_ip_addresses_nss(host).

$ git diff
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index aae2fe603..3b446ce76 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -1121,18 +1121,18 @@ class BindInstance(service.Service):

     def setup_resolv_conf(self):
         searchdomains = [self.domain]
-        nameservers = []
+        nameservers = set()
         resolve1_enabled = dnsforwarders.detect_resolve1_resolv_conf()

         for ip_address in self.ip_addresses:
             if ip_address.version == 4:
-                nameservers.append("127.0.0.1")
+                nameservers.add("127.0.0.1")
             elif ip_address.version == 6:
-                nameservers.append("::1")
+                nameservers.add("::1")

         try:
             tasks.configure_dns_resolver(
-                nameservers, searchdomains,
+                sorted(nameservers), searchdomains,
                 resolve1_enabled=resolve1_enabled, fstore=self.fstore
             )
         except IOError as e:
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index d1d8b3a64..ef58fd24c 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -1437,8 +1437,9 @@ def upgrade_bind(fstore):
     # resolve1's stub resolver config file.
     has_resolved_ipa_conf = os.path.isfile(paths.SYSTEMD_RESOLVED_IPA_CONF)
     if not has_resolved_ipa_conf and detect_resolve1_resolv_conf():
-        ip_addresses = installutils.get_server_ip_address(
-            api.env.host, True, False, [])
+        ip_addresses = installutils.resolve_ip_addresses_nss(
+            api.env.host
+        )
         bind.ip_addresses = ip_addresses
         bind.setup_resolv_conf()
         logger.info("Updated systemd-resolved configuration")

Metadata Update from @cheimes:
- Issue status updated to: Open (was: Closed)

2 years ago

master:

  • 6ba5a6a Require(post) systemd with resolved enabled on F33
  • 814328e Don't add 127.0.0.1 to resolv.conf twice
  • a3abae8 Simplify update code

ipa-4-8:

  • da301c2 Require(post) systemd with resolved enabled on F33
  • d1c43a9 Don't add 127.0.0.1 to resolv.conf twice
  • 01b5904 Simplify update code

Metadata Update from @cheimes:
- Issue close_status updated to: fixed
- Issue status updated to: Closed (was: Open)

2 years ago

Login to comment on this ticket.

Metadata