chiark / gitweb /
networkd: manager - read fallback DNS servers from config file
[elogind.git] / src / network / networkd-manager.c
index cc55f9a17a0307d74ef9c901c2bc3e0c2cf6bf53..ad36553f2b48e8979cce2d5c67cd46950a1281d2 100644 (file)
 #include <linux/if.h>
 #include <libkmod.h>
 
+#include "conf-parser.h"
 #include "path-util.h"
 #include "networkd.h"
+#include "network-internal.h"
 #include "libudev-private.h"
 #include "udev-util.h"
 #include "rtnl-util.h"
@@ -74,6 +76,95 @@ 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;
@@ -86,6 +177,14 @@ 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;
@@ -142,6 +241,7 @@ void manager_free(Manager *m) {
         Network *network;
         NetDev *netdev;
         Link *link;
+        Address *address;
 
         if (!m)
                 return;
@@ -157,6 +257,11 @@ 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);
@@ -485,15 +590,22 @@ int manager_update_resolv_conf(Manager *m) {
         HASHMAP_FOREACH(link, m->links, i) {
                 if (link->network && link->network->dns) {
                         Address *address;
-                        Iterator j;
 
-                        SET_FOREACH(address, link->network->dns, j) {
+                        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) {