]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: drop and warn duplicated Address= settings
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 1 Oct 2021 00:22:18 +0000 (09:22 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 4 Oct 2021 09:17:38 +0000 (18:17 +0900)
Fixes #20891.

src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-network.c

index f162fd5334a4eb4ce4ed00197ba447a3f98fca52..002827eb7845e6387c7611562a13c4985d4c8e72 100644 (file)
@@ -314,6 +314,12 @@ int address_compare_func(const Address *a1, const Address *a2) {
         }
 }
 
+DEFINE_PRIVATE_HASH_OPS(
+        address_hash_ops,
+        Address,
+        address_hash_func,
+        address_compare_func);
+
 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
         address_hash_ops_free,
         Address,
@@ -1910,12 +1916,43 @@ static int address_section_verify(Address *address) {
         return 0;
 }
 
-void network_drop_invalid_addresses(Network *network) {
+int network_drop_invalid_addresses(Network *network) {
+        _cleanup_set_free_ Set *addresses = NULL;
         Address *address;
+        int r;
 
         assert(network);
 
-        ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section)
-                if (address_section_verify(address) < 0)
+        ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section) {
+                Address *dup;
+
+                if (address_section_verify(address) < 0) {
+                        /* Drop invalid [Address] sections or Address= settings in [Network].
+                         * Note that address_free() will drop the address from addresses_by_section. */
                         address_free(address);
+                        continue;
+                }
+
+                /* Always use the setting specified later. So, remove the previously assigned setting. */
+                dup = set_remove(addresses, address);
+                if (dup) {
+                        _cleanup_free_ char *buf = NULL;
+
+                        (void) in_addr_prefix_to_string(address->family, &address->in_addr, address->prefixlen, &buf);
+                        log_warning("%s: Duplicated address %s is specified at line %u and %u, "
+                                    "dropping the address setting specified at line %u.",
+                                    dup->section->filename, strna(buf), address->section->line,
+                                    dup->section->line, dup->section->line);
+                        /* address_free() will drop the address from addresses_by_section. */
+                        address_free(dup);
+                }
+
+                /* Do not use address_hash_ops_free here. Otherwise, all address settings will be freed. */
+                r = set_ensure_put(&addresses, &address_hash_ops, address);
+                if (r < 0)
+                        return log_oom();
+                assert(r > 0);
+        }
+
+        return 0;
 }
index 80ceda94279a47d8bf48fb25a1563ac58b2d3e6d..0fd3163fc4ef4f2d3c66f75934260b6f9294b810 100644 (file)
@@ -93,7 +93,7 @@ int request_process_address(Request *req);
 
 int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, Manager *m);
 
-void network_drop_invalid_addresses(Network *network);
+int network_drop_invalid_addresses(Network *network);
 
 void address_hash_func(const Address *a, struct siphash *state);
 int address_compare_func(const Address *a1, const Address *a2);
index 9c01d1cb8947f4230831fba7c433a9f0df0b4265..bb7c1defe7d90a22480505c7e56005c5fed0f437 100644 (file)
@@ -121,6 +121,8 @@ static int network_resolve_stacked_netdevs(Network *network) {
 }
 
 int network_verify(Network *network) {
+        int r;
+
         assert(network);
         assert(network->filename);
 
@@ -299,7 +301,9 @@ int network_verify(Network *network) {
                 network->ipv6_proxy_ndp_addresses = set_free_free(network->ipv6_proxy_ndp_addresses);
         }
 
-        network_drop_invalid_addresses(network);
+        r = network_drop_invalid_addresses(network);
+        if (r < 0)
+                return r;
         network_drop_invalid_routes(network);
         network_drop_invalid_nexthops(network);
         network_drop_invalid_bridge_fdb_entries(network);