chiark / gitweb /
resolved: add daemon to manage resolv.conf
authorTom Gundersen <teg@jklm.no>
Sun, 18 May 2014 20:10:48 +0000 (22:10 +0200)
committerTom Gundersen <teg@jklm.no>
Mon, 19 May 2014 16:14:56 +0000 (18:14 +0200)
Also remove the equivalent functionality from networkd.

22 files changed:
.gitignore
Makefile-man.am
Makefile.am
configure.ac
man/resolved.conf.xml [new file with mode: 0644]
man/systemd-networkd.service.xml
man/systemd-resolved.service.xml [new file with mode: 0644]
src/network/.gitignore
src/network/networkd-link.c
src/network/networkd-manager.c
src/network/networkd-network.c
src/network/networkd.c
src/network/networkd.h
src/resolve/.gitignore [new file with mode: 0644]
src/resolve/Makefile [new symlink]
src/resolve/resolved-gperf.gperf [moved from src/network/networkd-gperf.gperf with 55% similarity]
src/resolve/resolved-manager.c [new file with mode: 0644]
src/resolve/resolved.c [new file with mode: 0644]
src/resolve/resolved.conf.in [moved from src/network/networkd.conf.in with 87% similarity]
src/resolve/resolved.h [new file with mode: 0644]
units/.gitignore
units/systemd-resolved.service.in [new file with mode: 0644]

index 3577c2a..908c563 100644 (file)
@@ -92,6 +92,7 @@
 /systemd-remount-api-vfs
 /systemd-remount-fs
 /systemd-reply-password
+/systemd-resolved
 /systemd-rfkill
 /systemd-run
 /systemd-shutdown
index ca7d209..6d57b75 100644 (file)
@@ -1131,6 +1131,18 @@ man/systemd-readahead.html: man/systemd-readahead-replay.service.html
 
 endif
 
+if ENABLE_RESOLVED
+MANPAGES += \
+       man/resolved.conf.5 \
+       man/systemd-resolved.service.8
+MANPAGES_ALIAS += \
+       man/systemd-resolved.8
+man/systemd-resolved.8: man/systemd-resolved.service.8
+man/systemd-resolved.html: man/systemd-resolved.service.html
+       $(html-alias)
+
+endif
+
 if ENABLE_RFKILL
 MANPAGES += \
        man/systemd-rfkill@.service.8
@@ -1483,6 +1495,7 @@ EXTRA_DIST += \
        man/nss-myhostname.xml \
        man/os-release.xml \
        man/pam_systemd.xml \
+       man/resolved.conf.xml \
        man/runlevel.xml \
        man/sd-daemon.xml \
        man/sd-id128.xml \
@@ -1581,6 +1594,7 @@ EXTRA_DIST += \
        man/systemd-random-seed.service.xml \
        man/systemd-readahead-replay.service.xml \
        man/systemd-remount-fs.service.xml \
+       man/systemd-resolved.service.xml \
        man/systemd-rfkill@.service.xml \
        man/systemd-run.xml \
        man/systemd-shutdownd.service.xml \
index 6e01188..f2a3bbd 100644 (file)
@@ -4194,6 +4194,51 @@ EXTRA_DIST += \
 endif
 
 # ------------------------------------------------------------------------------
+if ENABLE_RESOLVED
+systemd_resolved_SOURCES = \
+       src/resolve/resolved.h \
+       src/resolve/resolved.c \
+       src/resolve/resolved-manager.c
+
+nodist_systemd_resolved_SOURCES = \
+       src/resolve/resolved-gperf.c
+
+EXTRA_DIST += \
+       src/resolve/resolved-gperf.gperf
+
+CLEANFILES += \
+       src/resolve/resolved-gperf.c
+
+systemd_resolved_LDADD = \
+       libsystemd-label.la \
+       libsystemd-internal.la \
+       libsystemd-shared.la \
+       libsystemd-network.la
+
+rootlibexec_PROGRAMS += \
+       systemd-resolved
+
+nodist_systemunit_DATA += \
+       units/systemd-resolved.service
+
+EXTRA_DIST += \
+       units/systemd-resolved.service.in
+
+GENERAL_ALIASES += \
+       $(systemunitdir)/systemd-resolved.service $(pkgsysconfdir)/system/multi-user.target.wants/systemd-resolved.service
+
+nodist_pkgsysconf_DATA += \
+       src/resolve/resolved.conf
+
+EXTRA_DIST += \
+       src/resolve/resolved.conf.in
+
+CLEANFILES += \
+       src/resolve/resolved.conf
+
+endif
+
+# ------------------------------------------------------------------------------
 if ENABLE_NETWORKD
 rootlibexec_PROGRAMS += \
        systemd-networkd
@@ -4225,8 +4270,7 @@ libsystemd_networkd_core_la_SOURCES = \
 
 nodist_libsystemd_networkd_core_la_SOURCES = \
        src/network/networkd-network-gperf.c \
-       src/network/networkd-netdev-gperf.c \
-       src/network/networkd-gperf.c
+       src/network/networkd-netdev-gperf.c
 
 libsystemd_networkd_core_la_LIBADD = \
        libudev-internal.la \
@@ -4272,22 +4316,15 @@ GENERAL_ALIASES += \
        $(systemunitdir)/systemd-networkd.service $(pkgsysconfdir)/system/multi-user.target.wants/systemd-networkd.service \
        $(systemunitdir)/systemd-networkd.service $(pkgsysconfdir)/system/network-online.target.wants/systemd-networkd-wait-online.service
 
-nodist_pkgsysconf_DATA += \
-       src/network/networkd.conf
-
 EXTRA_DIST += \
        src/network/networkd-network-gperf.gperf \
        src/network/networkd-netdev-gperf.gperf \
-       src/network/networkd-gperf.gperf \
        units/systemd-networkd.service.in \
-       units/systemd-networkd-wait-online.service.in \
-       src/network/networkd.conf.in
+       units/systemd-networkd-wait-online.service.in
 
 CLEANFILES += \
        src/network/networkd-network-gperf.c \
-       src/network/networkd-netdev-gperf.c \
-       src/network/networkd-gperf.c \
-       src/network/networkd.conf
+       src/network/networkd-netdev-gperf.c
 endif
 
 # ------------------------------------------------------------------------------
index 469fc2d..9a849ff 100644 (file)
@@ -879,26 +879,34 @@ fi
 AM_CONDITIONAL(ENABLE_POLKIT, [test "x$have_polkit" = "xyes"])
 
 # ------------------------------------------------------------------------------
-have_networkd=no
-AC_ARG_ENABLE(networkd, AS_HELP_STRING([--disable-networkd], [disable networkd]))
-if test "x$enable_networkd" != "xno"; then
-        AC_DEFINE(ENABLE_NETWORKD, 1, [Define if networkd support is to be enabled])
-        have_networkd=yes
+have_resolved=no
+AC_ARG_ENABLE(resolved, AS_HELP_STRING([--disable-resolved], [disable resolve daemon]))
+if test "x$enable_resolved" != "xno"; then
+        have_resolved=yes
 fi
-AS_IF([test "x$have_networkd" = "xyes" -a "x$have_kmod" != "xyes"],
-      [AC_MSG_ERROR([networkd requires kmod])])
-AM_CONDITIONAL(ENABLE_NETWORKD, [test "x$have_networkd" = "xyes"])
+AM_CONDITIONAL(ENABLE_RESOLVED, [test "$have_resolved" = "yes"])
 
 AC_ARG_WITH(dns-servers,
         AS_HELP_STRING([--with-dns-servers=DNSSERVERS],
                 [Space-separated list of default DNS servers]),
-        [DNS_SERVERS="$withval"],
+        [NTP_SERVERS="$withval"],
         [DNS_SERVERS="8.8.8.8 8.8.4.4 2001:4860:4860::8888 2001:4860:4860::8844"])
 
 AC_DEFINE_UNQUOTED(DNS_SERVERS, ["$DNS_SERVERS"], [Default DNS Servers])
 AC_SUBST(DNS_SERVERS)
 
 # ------------------------------------------------------------------------------
+have_networkd=no
+AC_ARG_ENABLE(networkd, AS_HELP_STRING([--disable-networkd], [disable networkd]))
+if test "x$enable_networkd" != "xno"; then
+        AC_DEFINE(ENABLE_NETWORKD, 1, [Define if networkd support is to be enabled])
+        have_networkd=yes
+fi
+AS_IF([test "x$have_networkd" = "xyes" -a "x$have_kmod" != "xyes"],
+      [AC_MSG_ERROR([networkd requires kmod])])
+AM_CONDITIONAL(ENABLE_NETWORKD, [test "x$have_networkd" = "xyes"])
+
+# ------------------------------------------------------------------------------
 have_efi=no
 AC_ARG_ENABLE(efi, AS_HELP_STRING([--disable-efi], [disable EFI support]))
 if test "x$enable_efi" != "xno"; then
@@ -1201,6 +1209,7 @@ AC_MSG_RESULT([
         time epoch:              ${TIME_EPOCH}
         localed:                 ${have_localed}
         networkd:                ${have_networkd}
+        resolved:                ${have_resolved}
         default DNS servers:     ${DNS_SERVERS}
         coredump:                ${have_coredump}
         polkit:                  ${have_polkit}
diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml
new file mode 100644 (file)
index 0000000..04e510f
--- /dev/null
@@ -0,0 +1,91 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<!--
+  This file is part of systemd.
+
+  Copyright 2014 Tom Gundersen
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="resolved.conf" conditional='ENABLE_RESOLVED'>
+        <refentryinfo>
+                <title>resolved.conf</title>
+                <productname>systemd</productname>
+
+                <authorgroup>
+                        <author>
+                                <contrib>Developer</contrib>
+                                <firstname>Tom</firstname>
+                                <surname>Gundersen</surname>
+                                <email>teg@jklm.no</email>
+                        </author>
+                </authorgroup>
+        </refentryinfo>
+
+        <refmeta>
+                <refentrytitle>resolved.conf</refentrytitle>
+                <manvolnum>5</manvolnum>
+        </refmeta>
+
+        <refnamediv>
+                <refname>resolved.conf</refname>
+                <refpurpose>Network Name Resolution configuration file</refpurpose>
+        </refnamediv>
+
+        <refsynopsisdiv>
+                <para><filename>/etc/systemd/resolved.conf</filename></para>
+        </refsynopsisdiv>
+
+        <refsect1>
+                <title>Description</title>
+
+                <para>When starting, systemd-resolved will read the
+                configuration file <filename>resolved.conf</filename>.
+                This configuration file determines the fallback DNS
+                servers.</para>
+
+        </refsect1>
+
+        <refsect1>
+                <title>Options</title>
+
+                <variablelist class='network-directives'>
+
+                        <varlistentry>
+                                <term><varname>DNS=</varname></term>
+                                <listitem><para>A space separated list of IPv4 and IPv6
+                                addresses to be used as the fallback DNS servers. Note that
+                                the servers obtained from
+                                <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+                                take precedence. If this option is not given, a compiled-in
+                                list of DNS servers is used instead.</para></listitem>
+                        </varlistentry>
+
+                </variablelist>
+        </refsect1>
+
+        <refsect1>
+                  <title>See Also</title>
+                  <para>
+                        <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+                        <citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+                        <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+                  </para>
+        </refsect1>
+
+</refentry>
index 75ea1a4..0570798 100644 (file)
                 restarting networkd does not cut the network connection, and, in particular,
                 that it is safe to transition between the initrd and the real root,
                 and back.</para>
-
-                <para>Nameservers configured in networkd, or received over DHCP
-                are exposed in <filename>/run/systemd/network/resolv.conf</filename>.
-                This file should not be used directly, but only through a symlink
-                from <filename>/etc/resolv.conf</filename>.</para>
         </refsect1>
 
         <refsect1><title>Configuration Files</title>
diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml
new file mode 100644 (file)
index 0000000..cd73cb7
--- /dev/null
@@ -0,0 +1,85 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<!--
+  This file is part of systemd.
+
+  Copyright 2014 Tom Gundersen
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="systemd-resolved.service" conditional='ENABLE_RESOLVED'>
+
+        <refentryinfo>
+                <title>systemd-resolved.service</title>
+                <productname>systemd</productname>
+
+                <authorgroup>
+                        <author>
+                                <contrib>Developer</contrib>
+                                <firstname>Tom</firstname>
+                                <surname>Gundersen</surname>
+                                <email>teg@jklm.no</email>
+                        </author>
+                </authorgroup>
+        </refentryinfo>
+
+        <refmeta>
+                <refentrytitle>systemd-resolved.service</refentrytitle>
+                <manvolnum>8</manvolnum>
+        </refmeta>
+
+        <refnamediv>
+                <refname>systemd-resolved.service</refname>
+                <refname>systemd-resolved</refname>
+                <refpurpose>Network Name Resolution manager</refpurpose>
+        </refnamediv>
+
+        <refsynopsisdiv>
+                <para><filename>systemd-resolved.service</filename></para>
+                <para><filename>/usr/lib/systemd/systemd-resolved</filename></para>
+        </refsynopsisdiv>
+
+        <refsect1>
+                <title>Description</title>
+
+                <para><command>systemd-networkd</command> is a system
+                service that manages network name resolution. It does so by
+               generating <filename>/run/systemd/network/resolv.conf</filename>,
+               which may be symlinked from <filename>/etc/resolv.conf</filename>.
+               The contents is generated from the global settings in
+                <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+               the per-link static settings in <filename>.network</filename> files,
+               and the per-link dynamic settings received over DHCP. See
+                <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+               for more details.</para>
+
+                <para>Note that <filename>/run/systemd/network/resolv.conf</filename>
+                should not be used directly, but only through a symlink from
+               <filename>/etc/resolv.conf</filename>.</para>
+        </refsect1>
+
+        <refsect1>
+                <title>See Also</title>
+                <para>
+                       <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+                        <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+                        <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+                        <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+                </para>
+        </refsect1>
+
+</refentry>
index 04bce2e..8858596 100644 (file)
@@ -1,4 +1,2 @@
 /networkd-network-gperf.c
 /networkd-netdev-gperf.c
-/networkd-gperf.c
-/networkd.conf
index 8ce2dbd..5a7472b 100644 (file)
@@ -854,8 +854,6 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
         struct in_addr netmask;
         struct in_addr gateway;
         unsigned prefixlen;
-        struct in_addr *nameservers;
-        size_t nameservers_size;
         int r;
 
         assert(client);
@@ -920,15 +918,6 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
 
         link->dhcp_lease = lease;
 
-        if (link->network->dhcp_dns) {
-                r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
-                if (r >= 0) {
-                        r = manager_update_resolv_conf(link->manager);
-                        if (r < 0)
-                                log_error_link(link, "Failed to update resolv.conf");
-                }
-        }
-
         if (link->network->dhcp_mtu) {
                 uint16_t mtu;
 
index ad36553..2e3b4bb 100644 (file)
@@ -19,7 +19,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
 
-#include <resolv.h>
+#include <sys/socket.h>
 #include <linux/if.h>
 #include <libkmod.h>
 
@@ -76,95 +76,6 @@ static int setup_signals(Manager *m) {
         return 0;
 }
 
-static int set_fallback_dns(Manager *m, const char *string) {
-        char *word, *state;
-        size_t length;
-        int r;
-
-        assert(m);
-        assert(string);
-
-        FOREACH_WORD_QUOTED(word, length, string, state) {
-                _cleanup_address_free_ Address *address = NULL;
-                Address *tail;
-                _cleanup_free_ char *addrstr = NULL;
-
-                r = address_new_dynamic(&address);
-                if (r < 0)
-                        return r;
-
-                addrstr = strndup(word, length);
-                if (!addrstr)
-                        return -ENOMEM;
-
-                r = net_parse_inaddr(addrstr, &address->family, &address->in_addr);
-                if (r < 0) {
-                        log_debug("Ignoring invalid DNS address '%s'", addrstr);
-                        continue;
-                }
-
-                LIST_FIND_TAIL(addresses, m->fallback_dns, tail);
-                LIST_INSERT_AFTER(addresses, m->fallback_dns, tail, address);
-                address = NULL;
-        }
-
-        return 0;
-}
-
-int config_parse_dnsv(
-                const char *unit,
-                const char *filename,
-                unsigned line,
-                const char *section,
-                unsigned section_line,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-
-        Manager *m = userdata;
-        Address *address;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(m);
-
-        while ((address = m->fallback_dns)) {
-                LIST_REMOVE(addresses, m->fallback_dns, address);
-                address_free(address);
-        }
-
-        set_fallback_dns(m, rvalue);
-
-        return 0;
-}
-
-static int manager_parse_config_file(Manager *m) {
-        static const char fn[] = "/etc/systemd/networkd.conf";
-        _cleanup_fclose_ FILE *f = NULL;
-        int r;
-
-        assert(m);
-
-        f = fopen(fn, "re");
-        if (!f) {
-                if (errno == ENOENT)
-                        return 0;
-
-                log_warning("Failed to open configuration file %s: %m", fn);
-                return -errno;
-        }
-
-        r = config_parse(NULL, fn, f, "Network\0", config_item_perf_lookup,
-                         (void*) networkd_gperf_lookup, false, false, m);
-        if (r < 0)
-                log_warning("Failed to parse configuration file: %s", strerror(-r));
-
-        return r;
-}
-
 int manager_new(Manager **ret) {
         _cleanup_manager_free_ Manager *m = NULL;
         int r;
@@ -177,14 +88,6 @@ int manager_new(Manager **ret) {
         if (!m->state_file)
                 return -ENOMEM;
 
-        r = set_fallback_dns(m, DNS_SERVERS);
-        if (r < 0)
-                return r;
-
-        r = manager_parse_config_file(m);
-        if (r < 0)
-                return r;
-
         r = sd_event_default(&m->event);
         if (r < 0)
                 return r;
@@ -241,7 +144,6 @@ void manager_free(Manager *m) {
         Network *network;
         NetDev *netdev;
         Link *link;
-        Address *address;
 
         if (!m)
                 return;
@@ -257,11 +159,6 @@ void manager_free(Manager *m) {
         sd_event_source_unref(m->sigint_event_source);
         sd_event_unref(m->event);
 
-        while ((address = m->fallback_dns)) {
-                LIST_REMOVE(addresses, m->fallback_dns, address);
-                address_free(address);
-        }
-
         while ((link = hashmap_first(m->links)))
                 link_unref(link);
         hashmap_free(m->links);
@@ -522,102 +419,6 @@ int manager_bus_listen(Manager *m) {
         return 0;
 }
 
-static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) {
-        char buf[INET6_ADDRSTRLEN];
-        const char *address;
-
-        address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
-        if (!address) {
-                log_warning("Invalid DNS address. Ignoring.");
-                return;
-        }
-
-        if (*count == MAXNS)
-                fputs("# Too many DNS servers configured, the following entries "
-                      "will be ignored\n", f);
-
-        fprintf(f, "nameserver %s\n", address);
-
-        (*count) ++;
-}
-
-int manager_update_resolv_conf(Manager *m) {
-        _cleanup_free_ char *temp_path = NULL;
-        _cleanup_fclose_ FILE *f = NULL;
-        Link *link;
-        Iterator i;
-        unsigned count = 0;
-        const char *domainname = NULL;
-        int r;
-
-        assert(m);
-
-        r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
-        if (r < 0)
-                return r;
-
-        fchmod(fileno(f), 0644);
-
-        fputs("# This file is managed by systemd-networkd(8). Do not edit.\n#\n"
-              "# Third party programs must not access this file directly, but\n"
-              "# only through the symlink at /etc/resolv.conf. To manage\n"
-              "# resolv.conf(5) in a different way, replace the symlink by a\n"
-              "# static file or a different symlink.\n\n", f);
-
-        HASHMAP_FOREACH(link, m->links, i) {
-                if (link->dhcp_lease) {
-                        struct in_addr *nameservers;
-                        size_t nameservers_size;
-
-                        if (link->network->dhcp_dns) {
-                                r = sd_dhcp_lease_get_dns(link->dhcp_lease, &nameservers, &nameservers_size);
-                                if (r >= 0) {
-                                        unsigned j;
-
-                                        for (j = 0; j < nameservers_size; j++)
-                                                append_dns(f, &nameservers[j], AF_INET, &count);
-                                }
-                        }
-
-                        if (link->network->dhcp_domainname && !domainname) {
-                                r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
-                                if (r >= 0)
-                                       fprintf(f, "domain %s\n", domainname);
-                        }
-                }
-        }
-
-        HASHMAP_FOREACH(link, m->links, i) {
-                if (link->network && link->network->dns) {
-                        Address *address;
-
-                        LIST_FOREACH(addresses, address, link->network->dns) {
-                                append_dns(f, &address->in_addr.in,
-                                           address->family, &count);
-                        }
-                }
-        }
-
-        if (!count) {
-                Address *address;
-
-                LIST_FOREACH(addresses, address, m->fallback_dns)
-                        append_dns(f, &address->in_addr.in,
-                                   address->family, &count);
-        }
-
-        fflush(f);
-
-        if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
-                r = -errno;
-                unlink("/run/systemd/network/resolv.conf");
-                unlink(temp_path);
-                return r;
-        }
-
-        return 0;
-}
-
 int manager_save(Manager *m) {
         Link *link;
         Iterator i;
index 12107c9..1b8856a 100644 (file)
@@ -235,7 +235,7 @@ int network_apply(Manager *manager, Network *network, Link *link) {
         link->network = network;
 
         if (network->dns) {
-                r = manager_update_resolv_conf(manager);
+                r = link_save(link);
                 if (r < 0)
                         return r;
         }
index 6b3bf12..6985dca 100644 (file)
@@ -93,14 +93,6 @@ int main(int argc, char *argv[]) {
                 goto out;
         }
 
-        /* write out empty resolv.conf to avoid a
-         * dangling symlink */
-        r = manager_update_resolv_conf(m);
-        if (r < 0) {
-                log_error("Could not create resolv.conf: %s", strerror(-r));
-                goto out;
-        }
-
         sd_notify(false,
                   "READY=1\n"
                   "STATUS=Processing requests...");
index 30a29c7..3e4e1f2 100644 (file)
@@ -256,7 +256,6 @@ struct Manager {
         Hashmap *links;
         Hashmap *netdevs;
         LIST_HEAD(Network, networks);
-        LIST_HEAD(Address, fallback_dns);
 
         usec_t network_dirs_ts_usec;
         struct kmod_ctx *kmod_ctx;
@@ -278,18 +277,11 @@ int manager_rtnl_listen(Manager *m);
 int manager_udev_listen(Manager *m);
 int manager_bus_listen(Manager *m);
 
-int manager_update_resolv_conf(Manager *m);
 int manager_save(Manager *m);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
 #define _cleanup_manager_free_ _cleanup_(manager_freep)
 
-const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length);
-
-int config_parse_dnsv(const char *unit, const char *filename, unsigned line,
-                     const char *section, unsigned section_line, const char *lvalue,
-                     int ltype, const char *rvalue, void *data, void *userdata);
-
 /* NetDev */
 
 int netdev_load(Manager *manager);
diff --git a/src/resolve/.gitignore b/src/resolve/.gitignore
new file mode 100644 (file)
index 0000000..ca3016e
--- /dev/null
@@ -0,0 +1,2 @@
+/resolved-gperf.c
+/resolved.conf
diff --git a/src/resolve/Makefile b/src/resolve/Makefile
new file mode 120000 (symlink)
index 0000000..d0b0e8e
--- /dev/null
@@ -0,0 +1 @@
+../Makefile
\ No newline at end of file
similarity index 55%
rename from src/network/networkd-gperf.gperf
rename to src/resolve/resolved-gperf.gperf
index a5dfc40..71e9980 100644 (file)
@@ -1,17 +1,17 @@
 %{
 #include <stddef.h>
 #include "conf-parser.h"
-#include "networkd.h"
+#include "resolved.h"
 %}
 struct ConfigPerfItem;
 %null_strings
 %language=ANSI-C
 %define slot-name section_and_lvalue
-%define hash-function-name networkd_gperf_hash
-%define lookup-function-name networkd_gperf_lookup
+%define hash-function-name resolved_gperf_hash
+%define lookup-function-name resolved_gperf_lookup
 %readonly-tables
 %omit-struct-type
 %struct-type
 %includes
 %%
-Network.DNS,                    config_parse_dnsv,     0, offsetof(Manager, fallback_dns)
+Resolve.DNS,                    config_parse_dnsv,     0, offsetof(Manager, fallback_dns)
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
new file mode 100644 (file)
index 0000000..ae17399
--- /dev/null
@@ -0,0 +1,320 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Tom Gundersen <teg@jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ ***/
+
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <linux/if.h>
+
+#include "resolved.h"
+#include "event-util.h"
+#include "network-util.h"
+#include "sd-dhcp-lease.h"
+#include "dhcp-lease-internal.h"
+#include "network-internal.h"
+#include "conf-parser.h"
+#include "mkdir.h"
+
+static int set_fallback_dns(Manager *m, const char *string) {
+        char *word, *state;
+        size_t length;
+        int r;
+
+        assert(m);
+        assert(string);
+
+        FOREACH_WORD_QUOTED(word, length, string, state) {
+                _cleanup_free_ Address *address = NULL;
+                Address *tail;
+                _cleanup_free_ char *addrstr = NULL;
+
+                address = new0(Address, 1);
+                if (!address)
+                        return -ENOMEM;
+
+                addrstr = strndup(word, length);
+                if (!addrstr)
+                        return -ENOMEM;
+
+                r = net_parse_inaddr(addrstr, &address->family, &address->in_addr);
+                if (r < 0) {
+                        log_debug("Ignoring invalid DNS address '%s'", addrstr);
+                        continue;
+                }
+
+                LIST_FIND_TAIL(addresses, m->fallback_dns, tail);
+                LIST_INSERT_AFTER(addresses, m->fallback_dns, tail, address);
+                address = NULL;
+        }
+
+        return 0;
+}
+
+int config_parse_dnsv(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Manager *m = userdata;
+        Address *address;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(m);
+
+        while ((address = m->fallback_dns)) {
+                LIST_REMOVE(addresses, m->fallback_dns, address);
+                free(address);
+        }
+
+        set_fallback_dns(m, rvalue);
+
+        return 0;
+}
+
+static int manager_parse_config_file(Manager *m) {
+        static const char fn[] = "/etc/systemd/resolved.conf";
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
+
+        assert(m);
+
+        f = fopen(fn, "re");
+        if (!f) {
+                if (errno == ENOENT)
+                        return 0;
+
+                log_warning("Failed to open configuration file %s: %m", fn);
+                return -errno;
+        }
+
+        r = config_parse(NULL, fn, f, "Resolve\0", config_item_perf_lookup,
+                         (void*) resolved_gperf_lookup, false, false, m);
+        if (r < 0)
+                log_warning("Failed to parse configuration file: %s", strerror(-r));
+
+        return r;
+}
+
+int manager_new(Manager **ret) {
+        _cleanup_manager_free_ Manager *m = NULL;
+        int r;
+
+        m = new0(Manager, 1);
+        if (!m)
+                return -ENOMEM;
+
+        r = set_fallback_dns(m, DNS_SERVERS);
+        if (r < 0)
+                return r;
+
+        r = manager_parse_config_file(m);
+        if (r < 0)
+                return r;
+
+        r = sd_event_default(&m->event);
+        if (r < 0)
+                return r;
+
+        sd_event_add_signal(m->event, NULL, SIGTERM, NULL,  NULL);
+        sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
+
+        sd_event_set_watchdog(m->event, true);
+
+        *ret = m;
+        m = NULL;
+
+        return 0;
+}
+
+void manager_free(Manager *m) {
+        Address *address;
+
+        if (!m)
+                return;
+
+        sd_event_unref(m->event);
+
+        while ((address = m->fallback_dns)) {
+                LIST_REMOVE(addresses, m->fallback_dns, address);
+                free(address);
+        }
+
+        free(m);
+}
+
+static void append_dns(FILE *f, void *dns, unsigned char family, unsigned *count) {
+        char buf[INET6_ADDRSTRLEN];
+        const char *address;
+
+        assert(f);
+        assert(dns);
+        assert(count);
+
+        address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
+        if (!address) {
+                log_warning("Invalid DNS address. Ignoring.");
+                return;
+        }
+
+        if (*count == MAXNS)
+                fputs("# Too many DNS servers configured, the following entries "
+                      "may be ignored\n", f);
+
+        fprintf(f, "nameserver %s\n", address);
+
+        (*count) ++;
+}
+
+int manager_update_resolv_conf(Manager *m) {
+        _cleanup_free_ char *temp_path = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+         _cleanup_free_ unsigned *indices = NULL;
+        Address *address;
+        unsigned count = 0;
+        int n, r, i;
+
+        assert(m);
+
+        r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
+        if (r < 0)
+                return r;
+
+        fchmod(fileno(f), 0644);
+
+        fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
+              "# Third party programs must not access this file directly, but\n"
+              "# only through the symlink at /etc/resolv.conf. To manage\n"
+              "# resolv.conf(5) in a different way, replace the symlink by a\n"
+              "# static file or a different symlink.\n\n", f);
+
+        n = sd_network_get_ifindices(&indices);
+        if (n < 0)
+                n = 0;
+
+        for (i = 0; i < n; i++) {
+                _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
+                struct in_addr *nameservers;
+                struct in6_addr *nameservers6;
+                size_t nameservers_size;
+
+                r = sd_network_dhcp_use_dns(indices[i]);
+                if (r > 0) {
+                        r = sd_network_get_dhcp_lease(indices[i], &lease);
+                        if (r >= 0) {
+                                r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
+                                if (r >= 0) {
+                                        unsigned j;
+
+                                        for (j = 0; j < nameservers_size; j++)
+                                                append_dns(f, &nameservers[j], AF_INET, &count);
+                                }
+                        }
+                }
+
+                r = sd_network_get_dns(indices[i], &nameservers, &nameservers_size);
+                if (r >= 0) {
+                        unsigned j;
+
+                        for (j = 0; j < nameservers_size; j++)
+                                append_dns(f, &nameservers[j], AF_INET, &count);
+
+                        free(nameservers);
+                }
+
+                r = sd_network_get_dns6(indices[i], &nameservers6, &nameservers_size);
+                if (r >= 0) {
+                        unsigned j;
+
+                        for (j = 0; j < nameservers_size; j++)
+                                append_dns(f, &nameservers6[j], AF_INET6, &count);
+
+                        free(nameservers6);
+                }
+        }
+
+        LIST_FOREACH(addresses, address, m->fallback_dns)
+                append_dns(f, &address->in_addr, address->family, &count);
+
+        fflush(f);
+
+        if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
+                r = -errno;
+                unlink("/run/systemd/network/resolv.conf");
+                unlink(temp_path);
+                return r;
+        }
+
+        return 0;
+}
+
+static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t revents,
+                                         void *userdata) {
+        Manager *m = userdata;
+        int r;
+
+        assert(m);
+
+        r = manager_update_resolv_conf(m);
+        if (r < 0)
+                log_warning("Could not update resolv.conf: %s", strerror(-r));
+
+        sd_network_monitor_flush(m->network_monitor);
+
+        return 0;
+}
+
+int manager_network_monitor_listen(Manager *m) {
+        _cleanup_event_source_unref_ sd_event_source *event_source = NULL;
+        _cleanup_network_monitor_unref_ sd_network_monitor *monitor = NULL;
+        int r, fd, events;
+
+        r = sd_network_monitor_new(NULL, &monitor);
+        if (r < 0)
+                return r;
+
+        fd = sd_network_monitor_get_fd(monitor);
+        if (fd < 0)
+                return fd;
+
+        events = sd_network_monitor_get_events(monitor);
+        if (events < 0)
+                return events;
+
+        r = sd_event_add_io(m->event, &event_source, fd, events,
+                            &manager_network_event_handler, m);
+        if (r < 0)
+                return r;
+
+        m->network_monitor = monitor;
+        m->network_event_source = event_source;
+        monitor = NULL;
+        event_source = NULL;
+
+        return 0;
+}
diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c
new file mode 100644 (file)
index 0000000..82f43d6
--- /dev/null
@@ -0,0 +1,86 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Tom Gundersen <teg@jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-event.h"
+#include "sd-daemon.h"
+
+#include "resolved.h"
+
+#include "mkdir.h"
+
+int main(int argc, char *argv[]) {
+        _cleanup_manager_free_ Manager *m = NULL;
+        int r;
+
+        log_set_target(LOG_TARGET_AUTO);
+        log_parse_environment();
+        log_open();
+
+        umask(0022);
+
+        if (argc != 1) {
+                log_error("This program takes no arguments.");
+                r = -EINVAL;
+                goto out;
+        }
+
+        /* Always create the directory where resolv.conf will live */
+        r = mkdir_label("/run/systemd/network", 0755);
+        if (r < 0)
+                log_error("Could not create runtime directory: %s",
+                          strerror(-r));
+
+        r = manager_new(&m);
+        if (r < 0) {
+                log_error("Could not create manager: %s", strerror(-r));
+                goto out;
+        }
+
+        r = manager_network_monitor_listen(m);
+        if (r < 0) {
+                log_error("Could not listen for network events: %s", strerror(-r));
+                goto out;
+        }
+
+        /* write out default resolv.conf to avoid a
+         * dangling symlink */
+        r = manager_update_resolv_conf(m);
+        if (r < 0) {
+                log_error("Could not create resolv.conf: %s", strerror(-r));
+                goto out;
+        }
+
+        sd_notify(false,
+                  "READY=1\n"
+                  "STATUS=Processing requests...");
+
+        r = sd_event_loop(m->event);
+        if (r < 0) {
+                log_error("Event loop failed: %s", strerror(-r));
+                goto out;
+        }
+
+out:
+        sd_notify(false,
+                  "STATUS=Shutting down...");
+
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
similarity index 87%
rename from src/network/networkd.conf.in
rename to src/resolve/resolved.conf.in
index efe889a..a239195 100644 (file)
@@ -5,7 +5,7 @@
 #  the Free Software Foundation; either version 2.1 of the License, or
 #  (at your option) any later version.
 #
-# See networkd.conf(5) for details
+# See resolved.conf(5) for details
 
-[Network]
+[Resolve]
 #DNS=@DNS_SERVERS@
diff --git a/src/resolve/resolved.h b/src/resolve/resolved.h
new file mode 100644 (file)
index 0000000..984edc7
--- /dev/null
@@ -0,0 +1,69 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2013 Tom Gundersen <teg@jklm.no>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#pragma once
+
+#include "sd-event.h"
+#include "sd-network.h"
+
+#include "util.h"
+#include "list.h"
+
+typedef struct Address Address;
+typedef struct Manager Manager;
+
+struct Address {
+        unsigned char family;
+
+        union {
+                struct in_addr in;
+                struct in6_addr in6;
+        } in_addr;
+
+        LIST_FIELDS(Address, addresses);
+};
+
+struct Manager {
+        sd_event *event;
+
+        LIST_HEAD(Address, fallback_dns);
+
+        /* network */
+        sd_event_source *network_event_source;
+        sd_network_monitor *network_monitor;
+};
+
+/* Manager */
+
+int manager_new(Manager **ret);
+void manager_free(Manager *m);
+
+int manager_update_resolv_conf(Manager *m);
+int manager_network_monitor_listen(Manager *m);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
+#define _cleanup_manager_free_ _cleanup_(manager_freep)
+
+const struct ConfigPerfItem* resolved_gperf_lookup(const char *key, unsigned length);
+
+int config_parse_dnsv(const char *unit, const char *filename, unsigned line,
+                     const char *section, unsigned section_line, const char *lvalue,
+                     int ltype, const char *rvalue, void *data, void *userdata);
index fca17c9..b8c0845 100644 (file)
@@ -49,6 +49,7 @@
 /systemd-readahead-replay.service
 /systemd-reboot.service
 /systemd-remount-fs.service
+/systemd-resolved.service
 /systemd-rfkill@.service
 /systemd-shutdownd.service
 /systemd-suspend.service
diff --git a/units/systemd-resolved.service.in b/units/systemd-resolved.service.in
new file mode 100644 (file)
index 0000000..f4bbb7c
--- /dev/null
@@ -0,0 +1,21 @@
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+[Unit]
+Description=Network Name Resolution
+Documentation=man:systemd-resolved.service(8)
+After=systemd-networkd.service network.service
+
+[Service]
+Type=notify
+Restart=always
+RestartSec=0
+ExecStart=@rootlibexecdir@/systemd-resolved
+CapabilityBoundingSet=
+
+[Install]
+WantedBy=multi-user.target