network: add Reload() dbus method
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 23 Oct 2019 13:20:48 +0000 (22:20 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 24 Oct 2019 05:18:09 +0000 (14:18 +0900)
src/network/fuzz-network-parser.c
src/network/networkd-manager-bus.c
src/network/networkd-manager.c
src/network/networkd-network.c
src/network/networkd-network.h
src/network/org.freedesktop.network1.policy

index b056267..732b5b2 100644 (file)
@@ -23,6 +23,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
 
         fflush(f);
         assert_se(manager_new(&manager) >= 0);
-        (void) network_load_one(manager, network_config);
+        (void) network_load_one(manager, &manager->networks, network_config);
         return 0;
 }
index 7484fcf..6bc2c22 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <net/if.h>
+#include <sys/capability.h>
 
 #include "alloc-util.h"
 #include "bus-common-errors.h"
@@ -11,6 +12,7 @@
 #include "networkd-manager.h"
 #include "path-util.h"
 #include "strv.h"
+#include "user-util.h"
 
 static int method_list_links(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -187,6 +189,34 @@ static int bus_method_renew_link(sd_bus_message *message, void *userdata, sd_bus
         return call_link_method(userdata, message, bus_link_method_renew, error);
 }
 
+static int bus_method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Manager *manager = userdata;
+        Iterator i;
+        Link *link;
+        int r;
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.network1.reload",
+                                    NULL, true, UID_INVALID,
+                                    &manager->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Polkit will call us back */
+
+        r = network_reload(manager);
+        if (r < 0)
+                return r;
+
+        HASHMAP_FOREACH(link, manager->links, i) {
+                r = link_reconfigure(link);
+                if (r < 0)
+                        return r;
+        }
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
 const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_START(0),
 
@@ -209,6 +239,7 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("RevertLinkNTP", "i", NULL, bus_method_revert_link_ntp, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("RevertLinkDNS", "i", NULL, bus_method_revert_link_dns, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("RenewLink", "i", NULL, bus_method_renew_link, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("Reload", NULL, NULL, bus_method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
 
         SD_BUS_VTABLE_END
 };
index c70194f..36481bc 100644 (file)
@@ -1860,7 +1860,7 @@ int manager_load_config(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = network_load(m);
+        r = network_load(m, &m->networks);
         if (r < 0)
                 return r;
 
index 24d6556..85d6150 100644 (file)
@@ -314,7 +314,7 @@ int network_verify(Network *network) {
         return 0;
 }
 
-int network_load_one(Manager *manager, const char *filename) {
+int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) {
         _cleanup_free_ char *fname = NULL, *name = NULL;
         _cleanup_(network_unrefp) Network *network = NULL;
         _cleanup_fclose_ FILE *file = NULL;
@@ -488,36 +488,42 @@ int network_load_one(Manager *manager, const char *filename) {
                 log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
                                   network->filename);
 
-        r = ordered_hashmap_ensure_allocated(&manager->networks, &string_hash_ops);
+        struct stat stats;
+        if (stat(filename, &stats) < 0)
+                return -errno;
+        network->timestamp = timespec_load(&stats.st_mtim);
+
+        if (network_verify(network) < 0)
+                /* Ignore .network files that do not match the conditions. */
+                return 0;
+
+        r = ordered_hashmap_ensure_allocated(networks, &string_hash_ops);
         if (r < 0)
                 return r;
 
-        r = ordered_hashmap_put(manager->networks, network->name, network);
+        r = ordered_hashmap_put(*networks, network->name, network);
         if (r < 0)
                 return r;
 
-        if (network_verify(network) < 0)
-                return 0;
-
         network = NULL;
         return 0;
 }
 
-int network_load(Manager *manager) {
+int network_load(Manager *manager, OrderedHashmap **networks) {
         _cleanup_strv_free_ char **files = NULL;
         char **f;
         int r;
 
         assert(manager);
 
-        ordered_hashmap_clear_with_destructor(manager->networks, network_unref);
+        ordered_hashmap_clear_with_destructor(*networks, network_unref);
 
         r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
         if (r < 0)
                 return log_error_errno(r, "Failed to enumerate network files: %m");
 
         STRV_FOREACH(f, files) {
-                r = network_load_one(manager, *f);
+                r = network_load_one(manager, networks, *f);
                 if (r < 0)
                         log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
         }
@@ -525,6 +531,48 @@ int network_load(Manager *manager) {
         return 0;
 }
 
+int network_reload(Manager *manager) {
+        OrderedHashmap *new_networks = NULL;
+        Network *n, *old;
+        Iterator i;
+        int r;
+
+        assert(manager);
+
+        r = network_load(manager, &new_networks);
+        if (r < 0)
+                goto failure;
+
+        ORDERED_HASHMAP_FOREACH(n, new_networks, i) {
+                r = network_get_by_name(manager, n->name, &old);
+                if (r < 0)
+                        continue; /* The .network file is new. */
+
+                if (n->timestamp != old->timestamp)
+                        continue; /* The .network file is modified. */
+
+                if (!streq(n->filename, old->filename))
+                        continue;
+
+                r = ordered_hashmap_replace(new_networks, old->name, old);
+                if (r < 0)
+                        goto failure;
+
+                network_ref(old);
+                network_unref(n);
+        }
+
+        ordered_hashmap_free_with_destructor(manager->networks, network_unref);
+        manager->networks = new_networks;
+
+        return 0;
+
+failure:
+        ordered_hashmap_free_with_destructor(new_networks, network_unref);
+
+        return r;
+}
+
 static Network *network_free(Network *network) {
         IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
         RoutingPolicyRule *rule;
@@ -615,13 +663,9 @@ static Network *network_free(Network *network) {
         hashmap_free(network->prefixes_by_section);
         hashmap_free(network->rules_by_section);
 
-        if (network->manager) {
-                if (network->manager->networks && network->name)
-                        ordered_hashmap_remove(network->manager->networks, network->name);
-
-                if (network->manager->duids_requesting_uuid)
-                        set_remove(network->manager->duids_requesting_uuid, &network->duid);
-        }
+        if (network->manager &&
+            network->manager->duids_requesting_uuid)
+                set_remove(network->manager->duids_requesting_uuid, &network->duid);
 
         free(network->name);
 
index d169481..1ae560e 100644 (file)
@@ -54,6 +54,7 @@ struct Network {
 
         char *filename;
         char *name;
+        usec_t timestamp;
 
         unsigned n_ref;
 
@@ -283,8 +284,9 @@ Network *network_ref(Network *network);
 Network *network_unref(Network *network);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_unref);
 
-int network_load(Manager *manager);
-int network_load_one(Manager *manager, const char *filename);
+int network_load(Manager *manager, OrderedHashmap **networks);
+int network_reload(Manager *manager);
+int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename);
 int network_verify(Network *network);
 
 int network_get_by_name(Manager *manager, const char *name, Network **ret);
index 4a33f5a..79b418b 100644 (file)
                 <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
         </action>
 
+        <action id="org.freedesktop.network1.reload">
+                <description gettext-domain="systemd">Reload network settings</description>
+                <message gettext-domain="systemd">Authentication is required to reload network settings.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
+        </action>
+
 </policyconfig>