[systemd-commits] 6 commits - configure.ac .gitignore Makefile.am Makefile-man.am man/resolved.conf.xml man/systemd-networkd.service.xml man/systemd-resolved.service.xml src/libsystemd-network src/network src/resolve src/systemd units/.gitignore units/systemd-resolved.service.in

Tom Gundersen tomegun at kemper.freedesktop.org
Mon May 19 09:15:45 PDT 2014


 .gitignore                                   |    1 
 Makefile-man.am                              |   14 +
 Makefile.am                                  |   59 ++++
 configure.ac                                 |   27 +-
 man/resolved.conf.xml                        |   91 +++++++
 man/systemd-networkd.service.xml             |    5 
 man/systemd-resolved.service.xml             |   85 +++++++
 src/libsystemd-network/dhcp-lease-internal.h |    1 
 src/libsystemd-network/network-internal.c    |   95 ++++++++
 src/libsystemd-network/network-internal.h    |    4 
 src/libsystemd-network/sd-dhcp-lease.c       |   50 ----
 src/network/.gitignore                       |    2 
 src/network/networkd-gperf.gperf             |   17 -
 src/network/networkd-link.c                  |   40 ++-
 src/network/networkd-manager.c               |  201 ----------------
 src/network/networkd-network.c               |    2 
 src/network/networkd.c                       |    8 
 src/network/networkd.conf.in                 |   11 
 src/network/networkd.h                       |    8 
 src/network/sd-network.c                     |   67 +++++
 src/network/test-network.c                   |   35 ++
 src/resolve/.gitignore                       |    2 
 src/resolve/Makefile                         |    1 
 src/resolve/resolved-gperf.gperf             |   17 +
 src/resolve/resolved-manager.c               |  320 +++++++++++++++++++++++++++
 src/resolve/resolved.c                       |   86 +++++++
 src/resolve/resolved.conf.in                 |   11 
 src/resolve/resolved.h                       |   69 +++++
 src/systemd/sd-network.h                     |    9 
 units/.gitignore                             |    1 
 units/systemd-resolved.service.in            |   21 +
 31 files changed, 1026 insertions(+), 334 deletions(-)

New commits:
commit d408b506814a0f99590d946b3bf99b57ba78336b
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon May 19 16:14:10 2014 +0200

    networkd: fixup static DNS serialization

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 5a7472b..a90aff9 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -1979,7 +1979,7 @@ static void serialize_addresses(FILE *f, const char *key, Address *address) {
         LIST_FOREACH(addresses, ad, address) {
                 char buf[INET6_ADDRSTRLEN];
 
-                if (inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN))
+                if (inet_ntop(ad->family, &ad->in_addr, buf, INET6_ADDRSTRLEN))
                         fprintf(f, "%s%s", buf, (ad->addresses_next) ? " ": "");
         }
 

commit 81d98a39eb4cca743beba27f4ae21a0e199df785
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon May 19 17:44:38 2014 +0200

    sd-dhcp-lease/sd-network: modernization and fix leak

diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index 4993fe3..cf71f11 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -174,6 +174,7 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
                 free(lease->hostname);
                 free(lease->domainname);
                 free(lease->dns);
+                free(lease->ntp);
                 free(lease);
         }
 
diff --git a/src/network/sd-network.c b/src/network/sd-network.c
index 64e3aaa..7ae15ed 100644
--- a/src/network/sd-network.c
+++ b/src/network/sd-network.c
@@ -142,8 +142,8 @@ _public_ int sd_network_get_link_operational_state(unsigned index, char **state)
 }
 
 _public_ int sd_network_get_dhcp_lease(unsigned index, sd_dhcp_lease **ret) {
+        _cleanup_free_ char *p = NULL, *s = NULL;
         sd_dhcp_lease *lease;
-        char *p, *s = NULL;
         int r;
 
         assert_return(index, -EINVAL);
@@ -153,12 +153,10 @@ _public_ int sd_network_get_dhcp_lease(unsigned index, sd_dhcp_lease **ret) {
                 return -ENOMEM;
 
         r = parse_env_file(p, NEWLINE, "DHCP_LEASE", &s, NULL);
-        free(p);
 
-        if (r < 0) {
-                free(s);
+        if (r < 0)
                 return r;
-        } else if (!s)
+        else if (!s)
                 return -EIO;
 
         r = dhcp_lease_load(s, &lease);

commit 091a364c802e34a58f3260c9cb5db9b75c62215c
Author: Tom Gundersen <teg at jklm.no>
Date:   Sun May 18 22:10:48 2014 +0200

    resolved: add daemon to manage resolv.conf
    
    Also remove the equivalent functionality from networkd.

diff --git a/.gitignore b/.gitignore
index 3577c2a..908c563 100644
--- a/.gitignore
+++ b/.gitignore
@@ -92,6 +92,7 @@
 /systemd-remount-api-vfs
 /systemd-remount-fs
 /systemd-reply-password
+/systemd-resolved
 /systemd-rfkill
 /systemd-run
 /systemd-shutdown
diff --git a/Makefile-man.am b/Makefile-man.am
index ca7d209..6d57b75 100644
--- a/Makefile-man.am
+++ b/Makefile-man.am
@@ -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 at .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 at .service.xml \
 	man/systemd-run.xml \
 	man/systemd-shutdownd.service.xml \
diff --git a/Makefile.am b/Makefile.am
index 6e01188..f2a3bbd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
 
 # ------------------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 469fc2d..9a849ff 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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
index 0000000..04e510f
--- /dev/null
+++ b/man/resolved.conf.xml
@@ -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 at 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>
diff --git a/man/systemd-networkd.service.xml b/man/systemd-networkd.service.xml
index 75ea1a4..0570798 100644
--- a/man/systemd-networkd.service.xml
+++ b/man/systemd-networkd.service.xml
@@ -72,11 +72,6 @@
                 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
index 0000000..cd73cb7
--- /dev/null
+++ b/man/systemd-resolved.service.xml
@@ -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 at 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>
diff --git a/src/network/.gitignore b/src/network/.gitignore
index 04bce2e..8858596 100644
--- a/src/network/.gitignore
+++ b/src/network/.gitignore
@@ -1,4 +1,2 @@
 /networkd-network-gperf.c
 /networkd-netdev-gperf.c
-/networkd-gperf.c
-/networkd.conf
diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf
deleted file mode 100644
index a5dfc40..0000000
--- a/src/network/networkd-gperf.gperf
+++ /dev/null
@@ -1,17 +0,0 @@
-%{
-#include <stddef.h>
-#include "conf-parser.h"
-#include "networkd.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
-%readonly-tables
-%omit-struct-type
-%struct-type
-%includes
-%%
-Network.DNS,                    config_parse_dnsv,     0, offsetof(Manager, fallback_dns)
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 8ce2dbd..5a7472b 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -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;
 
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index ad36553..2e3b4bb 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -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;
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 12107c9..1b8856a 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -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;
         }
diff --git a/src/network/networkd.c b/src/network/networkd.c
index 6b3bf12..6985dca 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -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...");
diff --git a/src/network/networkd.conf.in b/src/network/networkd.conf.in
deleted file mode 100644
index efe889a..0000000
--- a/src/network/networkd.conf.in
+++ /dev/null
@@ -1,11 +0,0 @@
-#  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.
-#
-# See networkd.conf(5) for details
-
-[Network]
-#DNS=@DNS_SERVERS@
diff --git a/src/network/networkd.h b/src/network/networkd.h
index 30a29c7..3e4e1f2 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -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
index 0000000..ca3016e
--- /dev/null
+++ b/src/resolve/.gitignore
@@ -0,0 +1,2 @@
+/resolved-gperf.c
+/resolved.conf
diff --git a/src/resolve/Makefile b/src/resolve/Makefile
new file mode 120000
index 0000000..d0b0e8e
--- /dev/null
+++ b/src/resolve/Makefile
@@ -0,0 +1 @@
+../Makefile
\ No newline at end of file
diff --git a/src/resolve/resolved-gperf.gperf b/src/resolve/resolved-gperf.gperf
new file mode 100644
index 0000000..71e9980
--- /dev/null
+++ b/src/resolve/resolved-gperf.gperf
@@ -0,0 +1,17 @@
+%{
+#include <stddef.h>
+#include "conf-parser.h"
+#include "resolved.h"
+%}
+struct ConfigPerfItem;
+%null_strings
+%language=ANSI-C
+%define slot-name section_and_lvalue
+%define hash-function-name resolved_gperf_hash
+%define lookup-function-name resolved_gperf_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+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
index 0000000..ae17399
--- /dev/null
+++ b/src/resolve/resolved-manager.c
@@ -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 at 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
index 0000000..82f43d6
--- /dev/null
+++ b/src/resolve/resolved.c
@@ -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 at 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;
+}
diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in
new file mode 100644
index 0000000..a239195
--- /dev/null
+++ b/src/resolve/resolved.conf.in
@@ -0,0 +1,11 @@
+#  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.
+#
+# See resolved.conf(5) for details
+
+[Resolve]
+#DNS=@DNS_SERVERS@
diff --git a/src/resolve/resolved.h b/src/resolve/resolved.h
new file mode 100644
index 0000000..984edc7
--- /dev/null
+++ b/src/resolve/resolved.h
@@ -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 at 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);
diff --git a/units/.gitignore b/units/.gitignore
index fca17c9..b8c0845 100644
--- a/units/.gitignore
+++ b/units/.gitignore
@@ -49,6 +49,7 @@
 /systemd-readahead-replay.service
 /systemd-reboot.service
 /systemd-remount-fs.service
+/systemd-resolved.service
 /systemd-rfkill at .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
index 0000000..f4bbb7c
--- /dev/null
+++ b/units/systemd-resolved.service.in
@@ -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

commit 7dbf94a9c4dcdf9b56384e66eb2652fb61da5063
Author: Tom Gundersen <teg at jklm.no>
Date:   Sun May 18 22:05:09 2014 +0200

    sd-network: expose DNS information

diff --git a/src/network/sd-network.c b/src/network/sd-network.c
index 492e97c..64e3aaa 100644
--- a/src/network/sd-network.c
+++ b/src/network/sd-network.c
@@ -32,6 +32,7 @@
 #include "strv.h"
 #include "fileio.h"
 #include "sd-network.h"
+#include "network-internal.h"
 #include "dhcp-lease-internal.h"
 
 static int link_get_flags(unsigned index, unsigned *flags) {
@@ -169,6 +170,64 @@ _public_ int sd_network_get_dhcp_lease(unsigned index, sd_dhcp_lease **ret) {
         return 0;
 }
 
+_public_ int sd_network_get_dns(unsigned index, struct in_addr **addr, size_t *addr_size) {
+        _cleanup_free_ char *p = NULL, *s = NULL;
+        int r;
+
+        assert_return(index, -EINVAL);
+        assert_return(addr, -EINVAL);
+        assert_return(addr_size, -EINVAL);
+
+        if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE, "DNS", &s, NULL);
+        if (r < 0)
+                return r;
+        else if (!s)
+                return -EIO;
+
+        return deserialize_in_addrs(addr, addr_size, s);
+}
+
+_public_ int sd_network_get_dns6(unsigned index, struct in6_addr **addr, size_t *addr_size) {
+        _cleanup_free_ char *p = NULL, *s = NULL;
+        int r;
+
+        assert_return(index, -EINVAL);
+        assert_return(addr, -EINVAL);
+        assert_return(addr_size, -EINVAL);
+
+        if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE, "DNS", &s, NULL);
+        if (r < 0)
+                return r;
+        else if (!s)
+                return -EIO;
+
+        return deserialize_in6_addrs(addr, addr_size, s);
+}
+
+_public_ int sd_network_dhcp_use_dns(unsigned index) {
+        _cleanup_free_ char *p = NULL, *s = NULL;
+        int r;
+
+        assert_return(index, -EINVAL);
+
+        if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE, "DHCP_USE_DNS", &s, NULL);
+        if (r < 0)
+                return r;
+        else if (!s)
+                return -EIO;
+
+        return parse_boolean(s);
+}
+
 _public_ int sd_network_get_ifindices(unsigned **indices) {
         _cleanup_closedir_ DIR *d;
         int r = 0;
diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h
index d0b2ea3..860325a 100644
--- a/src/systemd/sd-network.h
+++ b/src/systemd/sd-network.h
@@ -80,6 +80,15 @@ int sd_network_link_is_loopback(unsigned index);
 /* Get DHCPv4 lease from ifindex. */
 int sd_network_get_dhcp_lease(unsigned index, sd_dhcp_lease **ret);
 
+/* Returns true if link is configured to respect DNS entries received by DHCP */
+int sd_network_dhcp_use_dns(unsigned index);
+
+/* Get IPv4 DNS entries statically configured for the link */
+int sd_network_get_dns(unsigned index, struct in_addr **addr, size_t *addr_size);
+
+/* Get IPv6 DNS entries statically configured for the link */
+int sd_network_get_dns6(unsigned index, struct in6_addr **addr, size_t *addr_size);
+
 /* Get all network interfaces' indices, and store them in *indices. Returns
  * the number of indices. If indices is NULL, only returns the number of indices. */
 int sd_network_get_ifindices(unsigned **indices);

commit 7374f9d87c710bc1ae3bfdb78a191a31c72d29b9
Author: Tom Gundersen <teg at jklm.no>
Date:   Sun May 18 22:04:14 2014 +0200

    networkd: link - serialize DNS information

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 87a8d9f..8ce2dbd 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -1976,6 +1976,27 @@ int link_update(Link *link, sd_rtnl_message *m) {
         return link_update_flags(link, m);
 }
 
+static void serialize_addresses(FILE *f, const char *key, Address *address) {
+        Address *ad;
+
+        assert(f);
+        assert(key);
+
+        if (!address)
+                return;
+
+        fprintf(f, "%s=", key);
+
+        LIST_FOREACH(addresses, ad, address) {
+                char buf[INET6_ADDRSTRLEN];
+
+                if (inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN))
+                        fprintf(f, "%s%s", buf, (ad->addresses_next) ? " ": "");
+        }
+
+        fputs("\n", f);
+}
+
 int link_save(Link *link) {
         _cleanup_free_ char *temp_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
@@ -2017,12 +2038,18 @@ int link_save(Link *link) {
                 "FLAGS=%u\n",
                 admin_state, oper_state, link->flags);
 
+        if (link->network)
+                serialize_addresses(f, "DNS", link->network->dns);
+
         if (link->dhcp_lease) {
                 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
                 if (r < 0)
                         goto finish;
 
-                fprintf(f, "DHCP_LEASE=%s\n", link->lease_file);
+                fprintf(f,
+                        "DHCP_LEASE=%s\n"
+                        "DHCP_USE_DNS=%s\n",
+                        link->lease_file, yes_no(link->network->dhcp_dns));
         } else
                 unlink(link->lease_file);
 

commit 09bee74d7a5f266b175baa19892fa84a9da51d7f
Author: Tom Gundersen <teg at jklm.no>
Date:   Sun May 18 22:02:42 2014 +0200

    sd-dhcp-lease: move in_addr (de)serialization to shared network code

diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h
index ba2fd73..297bacb 100644
--- a/src/libsystemd-network/dhcp-lease-internal.h
+++ b/src/libsystemd-network/dhcp-lease-internal.h
@@ -26,6 +26,7 @@
 #include <linux/if_packet.h>
 
 #include "refcnt.h"
+#include "util.h"
 
 #include "dhcp-protocol.h"
 
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index f3dc42f..261603f 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -361,3 +361,98 @@ int load_module(struct kmod_ctx *ctx, const char *mod_name) {
 
         return r;
 }
+
+void serialize_in_addrs(FILE *f, const char *key, struct in_addr *addresses, size_t size) {
+        unsigned i;
+
+        assert(f);
+        assert(key);
+        assert(addresses);
+        assert(size);
+
+        fprintf(f, "%s=", key);
+
+        for (i = 0; i < size; i++)
+                fprintf(f, "%s%s", inet_ntoa(addresses[i]),
+                        (i < (size - 1)) ? " ": "");
+
+        fputs("\n", f);
+}
+
+int deserialize_in_addrs(struct in_addr **ret, size_t *ret_size, const char *string) {
+        _cleanup_free_ struct in_addr *addresses = NULL;
+        size_t size = 0;
+        char *word, *state;
+        size_t len;
+
+        assert(ret);
+        assert(ret_size);
+        assert(string);
+
+        FOREACH_WORD(word, len, string, state) {
+                _cleanup_free_ char *addr_str = NULL;
+                struct in_addr *new_addresses;
+                int r;
+
+                new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
+                if (!new_addresses)
+                        return -ENOMEM;
+                else
+                        addresses = new_addresses;
+
+                addr_str = strndup(word, len);
+                if (!addr_str)
+                        return -ENOMEM;
+
+                r = inet_pton(AF_INET, addr_str, &(addresses[size]));
+                if (r <= 0)
+                        continue;
+
+                size ++;
+        }
+
+        *ret_size = size;
+        *ret = addresses;
+        addresses = NULL;
+
+        return 0;
+}
+
+int deserialize_in6_addrs(struct in6_addr **ret, size_t *ret_size, const char *string) {
+        _cleanup_free_ struct in6_addr *addresses = NULL;
+        size_t size = 0;
+        char *word, *state;
+        size_t len;
+
+        assert(ret);
+        assert(ret_size);
+        assert(string);
+
+        FOREACH_WORD(word, len, string, state) {
+                _cleanup_free_ char *addr_str = NULL;
+                struct in6_addr *new_addresses;
+                int r;
+
+                new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
+                if (!new_addresses)
+                        return -ENOMEM;
+                else
+                        addresses = new_addresses;
+
+                addr_str = strndup(word, len);
+                if (!addr_str)
+                        return -ENOMEM;
+
+                r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
+                if (r <= 0)
+                        continue;
+
+                size++;
+        }
+
+        *ret_size = size;
+        *ret = addresses;
+        addresses = NULL;
+
+        return 0;
+}
diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h
index 1c77d33..c08cddd 100644
--- a/src/libsystemd-network/network-internal.h
+++ b/src/libsystemd-network/network-internal.h
@@ -68,3 +68,7 @@ int net_parse_inaddr(const char *address, unsigned char *family, void *dst);
 int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]);
 
 int load_module(struct kmod_ctx *ctx, const char *mod_name);
+
+void serialize_in_addrs(FILE *f, const char *key, struct in_addr *addresses, size_t size);
+int deserialize_in_addrs(struct in_addr **addresses, size_t *size, const char *string);
+int deserialize_in6_addrs(struct in6_addr **addresses, size_t *size, const char *string);
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index 3e43ab6..4993fe3 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -36,6 +36,7 @@
 #include "dhcp-lease-internal.h"
 #include "sd-dhcp-lease.h"
 #include "sd-dhcp-client.h"
+#include "network-internal.h"
 
 int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
         assert_return(lease, -EINVAL);
@@ -307,46 +308,6 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
         return 0;
 }
 
-static void serialize_addresses(FILE *f, const char *key, struct in_addr *addresses, size_t size) {
-        unsigned i;
-
-        assert(key);
-        assert(addresses);
-        assert(size);
-
-        fputs("DNS=", f);
-
-        for (i = 0; i < size; i++)
-                fprintf(f, "%s%s", inet_ntoa(addresses[i]),
-                        (i < (size - 1)) ? " ": "");
-
-        fputs("\n", f);
-}
-
-static int deserialize_addresses(struct in_addr **addresses, size_t *size, const char *string) {
-        char *word, *state;
-        size_t len;
-
-        FOREACH_WORD(word, len, string, state) {
-                struct in_addr *new_addresses;
-                int r;
-
-                new_addresses = realloc(*addresses, (*size + 1) * sizeof(struct in_addr));
-                if (!new_addresses)
-                        return -ENOMEM;
-                else
-                        *addresses = new_addresses;
-
-                r = inet_aton(word, &(new_addresses[*size]));
-                if (r < 0)
-                        continue;
-
-                (*size)++;
-        }
-
-        return 0;
-}
-
 int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
         _cleanup_free_ char *temp_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
@@ -399,11 +360,11 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
 
         r = sd_dhcp_lease_get_dns(lease, &addresses, &addresses_size);
         if (r >= 0)
-                serialize_addresses(f, "DNS", addresses, addresses_size);
+                serialize_in_addrs(f, "DNS", addresses, addresses_size);
 
         r = sd_dhcp_lease_get_ntp(lease, &addresses, &addresses_size);
         if (r >= 0)
-                serialize_addresses(f, "NTP", addresses, addresses_size);
+                serialize_in_addrs(f, "NTP", addresses, addresses_size);
 
         r = sd_dhcp_lease_get_domainname(lease, &string);
         if (r >= 0)
@@ -507,13 +468,13 @@ int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
         }
 
         if (dns) {
-                r = deserialize_addresses(&lease->dns, &lease->dns_size, dns);
+                r = deserialize_in_addrs(&lease->dns, &lease->dns_size, dns);
                 if (r < 0)
                         return r;
         }
 
         if (ntp) {
-                r = deserialize_addresses(&lease->ntp, &lease->ntp_size, dns);
+                r = deserialize_in_addrs(&lease->ntp, &lease->ntp_size, dns);
                 if (r < 0)
                         return r;
         }
diff --git a/src/network/test-network.c b/src/network/test-network.c
index a0e04f8..eb6ebe7 100644
--- a/src/network/test-network.c
+++ b/src/network/test-network.c
@@ -20,6 +20,38 @@
 ***/
 
 #include "networkd.h"
+#include "network-internal.h"
+
+static void test_deserialize_in_addr(void) {
+        _cleanup_free_ struct in_addr *addresses = NULL;
+        _cleanup_free_ struct in6_addr *addresses6 = NULL;
+        struct in_addr  a, b, c;
+        struct in6_addr d, e, f;
+        size_t size;
+        const char *addresses_string = "192.168.0.1 0:0:0:0:0:FFFF:204.152.189.116 192.168.0.2 ::1 192.168.0.3 1:0:0:0:0:0:0:8";
+
+        assert_se(inet_pton(AF_INET, "0:0:0:0:0:FFFF:204.152.189.116", &a) == 0);
+        assert_se(inet_pton(AF_INET6, "192.168.0.1", &d) == 0);
+
+        assert_se(inet_pton(AF_INET, "192.168.0.1", &a) == 1);
+        assert_se(inet_pton(AF_INET, "192.168.0.2", &b) == 1);
+        assert_se(inet_pton(AF_INET, "192.168.0.3", &c) == 1);
+        assert_se(inet_pton(AF_INET6, "0:0:0:0:0:FFFF:204.152.189.116", &d) == 1);
+        assert_se(inet_pton(AF_INET6, "::1", &e) == 1);
+        assert_se(inet_pton(AF_INET6, "1:0:0:0:0:0:0:8", &f) == 1);
+
+        assert_se(deserialize_in_addrs(&addresses, &size, addresses_string) >= 0);
+        assert_se(size == 3);
+        assert_se(!memcmp(&a, &addresses[0], sizeof(struct in_addr)));
+        assert_se(!memcmp(&b, &addresses[1], sizeof(struct in_addr)));
+        assert_se(!memcmp(&c, &addresses[2], sizeof(struct in_addr)));
+
+        assert_se(deserialize_in6_addrs(&addresses6, &size, addresses_string) >= 0);
+        assert_se(size == 3);
+        assert_se(!memcmp(&d, &addresses6[0], sizeof(struct in6_addr)));
+        assert_se(!memcmp(&e, &addresses6[1], sizeof(struct in6_addr)));
+        assert_se(!memcmp(&f, &addresses6[2], sizeof(struct in6_addr)));
+}
 
 static void test_load_config(Manager *manager) {
 /*  TODO: should_reload, is false if the config dirs do not exist, so
@@ -43,7 +75,7 @@ static void test_network_get(Manager *manager, struct udev_device *loopback) {
 }
 
 static void test_address_equality(void) {
-        Address *a1, *a2;
+        _cleanup_address_free_ Address *a1 = NULL, *a2 = NULL;
 
         assert_se(address_new_dynamic(&a1) >= 0);
         assert_se(address_new_dynamic(&a2) >= 0);
@@ -92,6 +124,7 @@ int main(void) {
         struct udev *udev;
         struct udev_device *loopback;
 
+        test_deserialize_in_addr();
         test_address_equality();
 
         assert_se(manager_new(&manager) >= 0);



More information about the systemd-commits mailing list