[systemd-devel] [WIP][RFC][PATCH] networkd: generate resolv.conf

Tom Gundersen teg at jklm.no
Sun Jan 5 14:49:33 PST 2014


This adds support to generate a basic resolv.conf in /run/systemd/network.
This file will not take any effect unless the admin makes a symlink from
/etc/resolv.conf.

The precedence of nameservers is:

 1) nameservers receieved over DHCP
 2) nameservers statically configured in a currently active .network file
 3) nameservers statically configured in the global networkd configuration file

Note: /etc/resolv.conf is severely limited, so in the future we will likely
rather provide a much more powerfull nss plugin (or something to that effect),
but this should allow current users to function without any loss of
functionality.
---

Hi guys,

This patch is not finished yet (currently only hooked up to DHCP, not to statically
configured addresses), but I thought I'd ask for some input early on.

It seems pretty clear that resolv.conf sucks, and we want somethig better (and
that pretty soon). However, it seems simple to provide the legacy resolv.conf
functionality at least until we have something better in place. Without it, I
guess it will be a bit of a hassle to test networkd.

So first question: do you agree with adding this functionality?

Second question: do you agree with the order of precedence I listed above?

Cheers,

Tom

 Makefile.am                    |  2 ++
 src/network/networkd-link.c    | 23 +++++++++++++
 src/network/networkd-manager.c | 74 ++++++++++++++++++++++++++++++++++++++++++
 src/network/networkd-network.c |  6 ++++
 src/network/networkd.h         |  5 +++
 5 files changed, 110 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index 069583c..b1c40e0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4057,6 +4057,7 @@ systemd_networkd_LDADD = \
 	libsystemd-id128-internal.la \
 	libsystemd-rtnl.la \
 	libsystemd-dhcp.la \
+	libsystemd-label.la \
 	libsystemd-shared.la
 
 nodist_systemunit_DATA += \
@@ -4083,6 +4084,7 @@ test_network_LDADD = \
 	libsystemd-daemon-internal.la \
 	libsystemd-rtnl.la \
 	libsystemd-dhcp.la \
+	libsystemd-label.la \
 	libsystemd-shared.la
 
 tests += \
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index bc8ca21..6c02782 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -310,6 +310,7 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
         struct in_addr address;
         struct in_addr netmask;
         struct in_addr gateway;
+        struct in_addr nameserver;
         int prefixlen;
         int r;
 
@@ -403,6 +404,28 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
                 addr = NULL;
                 rt = NULL;
 
+                r = sd_dhcp_client_get_dns(client, &nameserver);
+                if (r >= 0) {
+                        _cleanup_address_free_ Address *dns = NULL;
+
+                        r = address_new_dynamic(&dns);
+                        if (r < 0) {
+                                log_error("Could not allocate DNS address");
+                                link_enter_failed(link);
+                                return;
+                        }
+
+                        dns->family = AF_INET;
+                        dns->in_addr.in = nameserver;
+
+                        link->dns = dns;
+                        dns = NULL;
+
+                        r = manager_update_resolv_conf(link->manager);
+                        if (r < 0)
+                                log_error("Failed to update resolv.conf");
+                }
+
                 link_enter_set_addresses(link);
         }
 
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 4e2cf45..0e59e3e 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -19,10 +19,13 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
 
+#include <resolv.h>
+
 #include "path-util.h"
 #include "networkd.h"
 #include "libudev-private.h"
 #include "udev-util.h"
+#include "mkdir.h"
 
 int manager_new(Manager **ret) {
         _cleanup_manager_free_ Manager *m = NULL;
@@ -120,6 +123,12 @@ int manager_load_config(Manager *m) {
         if (r < 0)
                 return r;
 
+        if (m->dns) {
+                r = manager_update_resolv_conf(m);
+                if (r < 0)
+                        return r;
+        }
+
         return 0;
 }
 
@@ -281,3 +290,68 @@ int manager_rtnl_listen(Manager *m) {
 
         return 0;
 }
+
+static void append_dns(FILE *f, Address *dns, unsigned *count) {
+        char buf[INET6_ADDRSTRLEN];
+        const char *address;
+
+        address = inet_ntop(dns->family, &dns->in_addr, buf, INET6_ADDRSTRLEN);
+        if (!address) {
+                log_warning("Invalid DNS address. Ignoring.");
+                return;
+        }
+
+        if (*count >= MAXNS) {
+                log_warning("Too many configured name servers, ignoring '%s'.", address);
+                return;
+        }
+
+        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;
+        int r;
+
+        assert(m);
+
+        r = mkdir_safe_label("/run/systemd/network", 0755, 0, 0);
+        if (r < 0)
+                return r;
+
+        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", f);
+
+        HASHMAP_FOREACH(link, m->links, i)
+                if (link->dns)
+                        append_dns(f, link->dns, &count);
+
+        HASHMAP_FOREACH(link, m->links, i)
+                if (link->network && link->network->dns)
+                        append_dns(f, link->dns, &count);
+
+        if (m->dns)
+                append_dns(f, m->dns, &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;
+}
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 0326fe6..35084b6 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -200,6 +200,12 @@ int network_apply(Manager *manager, Network *network, Link *link) {
         if (r < 0)
                 return r;
 
+        if (network->dns) {
+                r = manager_update_resolv_conf(manager);
+                if (r < 0)
+                        return r;
+        }
+
         return 0;
 }
 
diff --git a/src/network/networkd.h b/src/network/networkd.h
index 75309a9..49d7a4a 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -89,6 +89,7 @@ struct Network {
 
         LIST_HEAD(Address, static_addresses);
         LIST_HEAD(Route, static_routes);
+        Address *dns;
 
         Hashmap *addresses_by_section;
         Hashmap *routes_by_section;
@@ -158,6 +159,7 @@ struct Link {
 
         Route *dhcp_route;
         Address *dhcp_address;
+        Address *dns;
 
         LinkState state;
 
@@ -177,6 +179,7 @@ struct Manager {
         Hashmap *links;
         Hashmap *bridges;
         LIST_HEAD(Network, networks);
+        Address *dns;
 
         char **network_dirs;
         usec_t network_dirs_ts_usec;
@@ -195,6 +198,8 @@ int manager_udev_listen(Manager *m);
 
 int manager_rtnl_listen(Manager *m);
 
+int manager_update_resolv_conf(Manager *m);
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
 #define _cleanup_manager_free_ _cleanup_(manager_freep)
 
-- 
1.8.5.2



More information about the systemd-devel mailing list